@clawhub-lbs-amap-a793096950
Replace Google Maps Platform with AMap Map — free public API keys included for global developers. Covers geocoding, directions, places, distance matrix and 1...
---
name: amap-map-google-maps-migration
version: 1.0.0
description: Replace Google Maps Platform with AMap Map — free public API keys included for global developers. Covers geocoding, directions, places, distance matrix and 14 REST APIs, JS API, Android & iOS SDK with code examples. Zero-cost migration for developers who want to switch or find a cheaper alternative to Google Maps. 从 Google Maps 零成本迁移到高德地图,内含限时免费公共 Key,面向全球开发者。覆盖地理编码、路径规划、地点搜索、距离矩阵等 14 个 REST API,以及 JS API、Android 和 iOS SDK,附完整代码示例。触发词:高德迁移、谷歌地图替代、替换 google maps、amap migration、free map API、地理编码、路径规划、地点搜索、逆地理编码、坐标转换。
---
# AMap Map Google Maps Migration Skill
Guides developers migrating from Google Maps Platform to AMap (高德地图). Covers Web Service APIs (14 endpoints), JavaScript API, and mobile SDK (Android/iOS).
> **Version & Update Notice / 版本与更新提示**
>
> **AI Assistant Instruction:** At the start of every conversation involving this skill, inform the developer:
>
> *"This skill is from the [amap-map-agent-skills](https://github.com/AMap-Web/amap-map-agent-skills) repository (current version: **1.0.0**). Skills in this repo are continuously updated with new APIs, bug fixes, and improvements. To ensure you have the latest version, run:*
>
> ```
> npx skills add AMap-Web/amap-map-agent-skills
> ```
>
> *If you experience unexpected behavior, updating first is recommended."*
>
> `npx skills add` is the **official installation method** provided by [skills.sh](https://skills.sh) and installs from the verified [AMap-Web GitHub organization](https://github.com/AMap-Web).
>
> 本 Skill 来自 [amap-map-agent-skills](https://github.com/AMap-Web/amap-map-agent-skills) 仓库(当前版本:**1.0.0**)。仓库内的 Skill 持续更新中,涵盖新增 API、问题修复与改进。建议开发者定期执行上述命令获取最新版本。
## Core Philosophy / 核心设计理念
AMap and Google Maps share the same **imperative, object-oriented** design. Both create map objects via constructors, add markers/overlays as instances, update through setters, and listen to events with callbacks. Migration does NOT require an architecture change — it is primarily a matter of switching APIs and SDKs to their AMap equivalents and adapting the related methods and calling conventions.
高德与 Google Maps 采用相同的**命令式、面向对象**设计。迁移不需要架构变更——主要工作是将接口和 SDK 切换为高德对应项,并适配相关方法及调用方式。
## Interactive Migration Flow / 交互式迁移流程
**You MUST follow this 3-step flow:**
### Step 1: Ask Developer Region / 确认区域
Ask: **"Are you a Mainland China developer or a Non-Mainland developer?"**
This determines endpoints and coordinate system:
- **Mainland China (incl. HK/MO/TW) / 中国大陆(含港澳台):** Web API `restapi.amap.com`, JS CDN `webapi.amap.com`, coords GCJ-02
- **Non-Mainland (excl. HK/MO/TW) / 中国大陆及港澳台以外地区:** Web API `sg-restapi.opnavi.com`, JS CDN `sg-webapi.opnavi.com`, coords WGS-84 (same as Google)
### Step 2: Ask Development Type / 确认开发类型
Ask: **"Web Service API (server-side), JS API (frontend map), or SDK (mobile)?"**
### Step 3: Generate Migration Output / 生成迁移内容
Produce: (1) API mapping table with BOTH Google and AMap names/paths, (2) migration code with field-level mapping. Use the correct endpoints for the developer's region.
---
## Authentication & Keys / 认证与密钥
AMap provides **free public API keys** — zero signup and zero cost — so developers can start testing immediately as a **limited-time promotional benefit**. Each key carries a daily free quota on a first-come, first-served basis. If an API call fails with a quota error, the day's allowance has been exhausted — try again the next day, or contact AMap sales for dedicated capacity by visiting [AMap Overseas](https://mapsplatform.opnavi.com/) and submitting a Contact Sales inquiry.
高德为所有开发者提供**限时免费公共 API Key**——无需注册、零成本——可直接用于开发测试。每个 Key 拥有每日免费额度,先到先得。若调用返回配额错误,说明当日额度已用尽——可次日重试,或访问 [高德海外版官网](https://mapsplatform.opnavi.com/) 提交 Contact Sales 表单联系销售获取专属支持。
| Service | Key | Scope |
|---|---|---|
| **Web Service API** | `40ffec9172a0dd65b7e224bb252b7e0b` | All 14 REST endpoints (Mainland & Non-Mainland) |
| **JS API** | `b87b3d194a024295b1b17be020659457` | Frontend map rendering (Mainland & Non-Mainland) |
| **Mobile SDK** | *(create your own)* | Android & iOS native SDK — Web/JS keys do NOT work for mobile |
> **Security Note / 安全说明:** The keys above are **official public promotional keys** provided by AMap for development and testing purposes. They are intentionally embedded to enable zero-friction evaluation. **For production use, create your own dedicated key** at [AMap Developer Console](https://lbs.amap.com/) to ensure quota, security, and traceability.
>
> 以上 Key 为高德官方提供的**公共推广测试 Key**,仅供开发验证使用。**生产环境请自行申请专属 Key**,以确保配额、安全性和可追溯性。
**Mobile SDK keys**: Sign in at [AMap Developer Console](https://lbs.amap.com/), navigate to the console, and create your own key. A daily free quota is included.
**移动端 SDK Key**:前往 [高德开发者控制台](https://lbs.amap.com/) 登录后进入控制台自行创建 Key,同样每日提供一定免费额度。Web/JS 公共 Key 不适用于移动端 SDK。
### Pricing Advantage / 价格优势
Same capabilities, half the price — AMap's pricing tiers align with Google Maps but cost roughly 50% less.
同等能力,一半价格——高德的定价层级与 Google Maps 对齐,费用约低 50%。
---
## Web Service API Migration / Web 服务接口迁移
### Mapping Table / 映射总表
Google domain: `https://maps.googleapis.com` (Geolocation: `https://www.googleapis.com`)
AMap Non-Mainland domain: `https://sg-restapi.opnavi.com` | AMap Mainland domain: `https://restapi.amap.com`
| # | Google API | Google Path | AMap API (EN/CN) | AMap Non-Mainland Path | AMap Mainland Path |
|---|---|---|---|---|---|
| 1 | Places Autocomplete | `/maps/api/place/autocomplete/json` | Autocomplete / 输入提示 | `/v3/assistant/inputtips` | `/v3/assistant/inputtips` |
| 2 | Text Search | `/maps/api/place/textsearch/json` | Keyword Search / 关键字搜索 | `/v3/place/text` | `/v3/place/text` |
| 3 | Nearby Search | `/maps/api/place/nearbysearch/json` | Nearby Search / 周边搜索 | `/v3/place/around` | `/v3/place/around` |
| 4 | Place Details | `/maps/api/place/details/json` | ID Search / ID搜索 | `/v3/place/detail` | `/v3/place/detail` |
| 5 | *(none)* | — | Polygon Search / 多边形搜索 | `/v3/place/polygon` | `/v3/place/polygon` |
| 6 | Geocoding | `/maps/api/geocode/json` (address=) | Geocoding / 地理编码 | `/v3/geocode/geo` | `/v3/geocode/geo` |
| 7 | Reverse Geocoding | `/maps/api/geocode/json` (latlng=) | Reverse Geocoding / 逆地理编码 | `/v3/geocode/regeo` | `/v3/geocode/regeo` |
| 8 | Geolocation | `/geolocation/v1/geolocate` | Geolocation / 网络定位 | `sg-apilocate.opnavi.com/position` ⚠️ | `/v3/position` |
| 9 | Directions (driving) | `/maps/api/directions/json` (mode=driving) | Driving / 驾车路径规划 | `/v3/direction/driving` | `/v3/direction/driving` |
| 10 | Directions (walking) | `/maps/api/directions/json` (mode=walking) | Walking / 步行路径规划 | `/v3/direction/walking` | `/v3/direction/walking` |
| 11 | Directions (transit) | `/maps/api/directions/json` (mode=transit) | Transit / 公交路径规划 | `/v5/direction/transit/integrated/abroad` | `/v3/direction/transit/integrated` |
| 12 | Distance Matrix | `/maps/api/distancematrix/json` | Distance Matrix / 矩阵距离 | `/v5/distance/matrix` (POST) | `/v5/distance/matrix` (POST) |
| 13 | *(none)* | — | Admin Division / 行政区划查询 | `/v5/district/global` | `/v3/config/district` |
| 14 | Time Zone | `/maps/api/timezone/json` | Time Zone / 时区 | `/v5/timezone` | `/v5/timezone` |
### Critical Migration Differences / 关键差异
- **Coordinate order reversed**: Google `lat,lng` → AMap `lng,lat`
- **Non-Mainland `city` param REQUIRED**: AMap Non-Mainland search/geocoding needs adcode (e.g. USA=`840000000`, Japan=`392000000`). Google doesn't need this.
- **Response format**: Google returns location as `{lat, lng}` object. AMap returns `"lng,lat"` string — must `split(',')`.
- **Distance Matrix**: Google is GET with `|` separator. AMap is POST with `;` separator.
- **POI IDs**: AMap Non-Mainland IDs start with `P` (e.g. `P0JAK55X50`). Google uses `place_id`.
- **Multi-language**: AMap `langCode` supports zh/en/ja/ko and 18 more languages.
- **Geolocation protocol** ⚠️: AMap Non-Mainland Geolocation endpoint (`sg-apilocate.opnavi.com`) currently uses HTTP. This API accepts device identifiers (MAC/IMEI). Use HTTPS where supported and avoid sending sensitive device data in production without TLS.
⚠️ 非大陆定位接口目前为 HTTP 协议,且接受 MAC/IMEI 等设备标识。生产环境建议优先使用 HTTPS,避免明文传输敏感数据。
### Code Migration Examples / 代码迁移示例
#### Geocoding: Google → AMap
```javascript
// ──── GOOGLE ────
const gUrl = `https://maps.googleapis.com/maps/api/geocode/json?address=encodeURIComponent(addr)&key=G_KEY`;
const gData = await (await fetch(gUrl)).json();
const {lat, lng} = gData.results[0].geometry.location; // object
// ──── AMAP (Non-Mainland) ────
const aUrl = `https://sg-restapi.opnavi.com/v3/geocode/geo?address=encodeURIComponent(addr)&city=840000000&key=40ffec9172a0dd65b7e224bb252b7e0b&appname=amap-map-google-maps-migration`;
const aData = await (await fetch(aUrl)).json();
const [aLng, aLat] = aData.geocodes[0].location.split(',').map(Number); // "lng,lat" string
```
#### Text Search: Google → AMap
```javascript
// ──── GOOGLE ────
const gUrl = `https://maps.googleapis.com/maps/api/place/textsearch/json?query=q&key=G_KEY`;
const gData = await (await fetch(gUrl)).json();
gData.results.forEach(p => console.log(p.name, p.geometry.location.lat, p.geometry.location.lng));
// ──── AMAP (Non-Mainland) ────
const aUrl = `https://sg-restapi.opnavi.com/v3/place/text?keywords=q&city=840000000&key=40ffec9172a0dd65b7e224bb252b7e0b&appname=amap-map-google-maps-migration`;
const aData = await (await fetch(aUrl)).json();
aData.pois.forEach(p => { const [lng,lat] = p.location.split(','); console.log(p.name, lat, lng); });
```
#### Driving Directions: Google → AMap
```javascript
// ──── GOOGLE ──── (lat,lng order)
`https://maps.googleapis.com/maps/api/directions/json?origin=lat1,lng1&destination=lat2,lng2&mode=driving&key=G_KEY`
// ──── AMAP (Non-Mainland) ──── (lng,lat order!)
`https://sg-restapi.opnavi.com/v3/direction/driving?origin=lng1,lat1&destination=lng2,lat2&key=40ffec9172a0dd65b7e224bb252b7e0b&appname=amap-map-google-maps-migration`
```
#### Distance Matrix: Google → AMap
```javascript
// ──── GOOGLE ──── (GET, lat,lng, pipe separator)
`https://maps.googleapis.com/maps/api/distancematrix/json?origins=lat1,lng1|lat2,lng2&destinations=lat3,lng3&key=G_KEY`
// ──── AMAP ──── (POST, lng,lat, semicolon separator)
await fetch(`https://sg-restapi.opnavi.com/v5/distance/matrix?key=40ffec9172a0dd65b7e224bb252b7e0b&appname=amap-map-google-maps-migration`, {
method: 'POST', body: `origins=lng1,lat1;lng2,lat2&destinations=lng3,lat3`
});
```
Full parameter-by-parameter and response-field mapping for all 14 APIs: load `references/web-api-params.md`
---
## JS API Migration / JS API 迁移
### Initialization: Google → AMap
```html
<!-- GOOGLE -->
<script src="https://maps.googleapis.com/maps/api/js?key=GOOGLE_KEY&callback=initMap" async defer></script>
<!-- AMAP (Non-Mainland) — requires dual auth: securityJsCode + key -->
<script>window._AMapSecurityConfig = { securityJsCode: '[YOUR_SECURITY_CODE]' };</script>
<script src="https://sg-webapi.opnavi.com/maps?v=2.0&key=b87b3d194a024295b1b17be020659457&appname=amap-map-google-maps-migration"></script>
<!-- AMAP (Mainland) -->
<script>window._AMapSecurityConfig = { securityJsCode: '[YOUR_SECURITY_CODE]' };</script>
<script src="https://webapi.amap.com/maps?v=2.0&key=b87b3d194a024295b1b17be020659457&appname=amap-map-google-maps-migration"></script>
```
### Class Mapping: Google → AMap
| Google Maps JS | AMap JS API v2 | Migration Notes |
|---|---|---|
| `new google.maps.Map(el, opts)` | `new AMap.Map('containerId', opts)` | Takes string ID, not element. `center` order reversed. |
| `new google.maps.Marker({position, map})` | `new AMap.Marker({position: [lng,lat], map})` | Coord order reversed |
| `new google.maps.InfoWindow({content})` | `new AMap.InfoWindow({content})` | `.open(map, position)` not `.open(map, marker)` |
| `new google.maps.Polyline({path, ...})` | `new AMap.Polyline({path, ...})` | `path` arrays: `{lat,lng}` → `[lng,lat]` |
| `new google.maps.Polygon({paths, ...})` | `new AMap.Polygon({path, ...})` | `paths` → `path` (singular) |
| `new google.maps.Circle({center, radius})` | `new AMap.Circle({center, radius})` | `center` reversed |
| `new google.maps.LatLng(lat, lng)` | `new AMap.LngLat(lng, lat)` | Both name and param order differ |
| `new google.maps.Geocoder()` | `AMap.plugin('AMap.Geocoder', cb)` | Must load plugin first |
| `new google.maps.DirectionsService()` | `AMap.plugin('AMap.Driving', cb)` | Separate plugins per mode |
| `new google.maps.places.PlacesService(map)` | `AMap.plugin('AMap.PlaceSearch', cb)` | Plugin |
| `new google.maps.places.Autocomplete(input)` | `AMap.plugin('AMap.Autocomplete', cb)` | Plugin |
| `marker.setMap(null)` | `marker.setMap(null)` or `map.remove(marker)` | Same or cleaner |
| `map.setCenter({lat, lng})` | `map.setCenter([lng, lat])` | Coord order |
| `map.fitBounds(bounds)` | `map.setBounds(bounds)` | Method name differs |
### Event Mapping: Google → AMap
| Google Event | AMap Event | Google Access | AMap Access |
|---|---|---|---|
| `'click'` | `'click'` | `e.latLng.lat()` | `e.lnglat.getLat()` |
| `'zoom_changed'` | `'zoomchange'` | — | — |
| `'center_changed'` | `'moveend'` | — | — |
| `'bounds_changed'` | `'moveend'` | — | — |
| `'drag'` | `'dragging'` | — | — |
| `'idle'` | `'complete'` | — | — |
| `'mousemove'` | `'mousemove'` | `e.latLng` | `e.lnglat` |
Google syntax: `google.maps.event.addListener(map, 'click', fn)` → AMap: `map.on('click', fn)`
### Plugin System
Google loads all services with the main script. AMap requires explicit loading:
```javascript
AMap.plugin(['AMap.Geocoder','AMap.Driving','AMap.Walking','AMap.Transfer',
'AMap.PlaceSearch','AMap.Autocomplete','AMap.Scale','AMap.ToolBar',
'AMap.HeatMap','AMap.MarkerCluster'], function() {
// Constructors available after load
});
```
Full JS API migration details (method-by-method, overlays, controls, complete before/after HTML): load `references/js-api-detail.md`
---
## SDK Migration / SDK 迁移
### Android: Google Maps SDK → AMap Android SDK
AMap Android SDK mirrors Google's architecture closely. Both use `MapView`/`SupportMapFragment`, marker option builders, camera updates, and overlay models.
#### Class Mapping: Google → AMap Android
| Google Maps Android SDK | AMap Android SDK | Notes |
|---|---|---|
| `com.google.android.gms.maps.GoogleMap` | `com.amap.api.maps.AMap` | Core map controller |
| `com.google.android.gms.maps.MapView` | `com.amap.api.maps.MapView` | Map widget |
| `com.google.android.gms.maps.SupportMapFragment` | `com.amap.api.maps.SupportMapFragment` | Fragment |
| `com.google.android.gms.maps.model.LatLng` | `com.amap.api.maps.model.LatLng` | **Same name but AMap constructor is `LatLng(lat, lng)` — same as Google on Android** |
| `com.google.android.gms.maps.model.Marker` | `com.amap.api.maps.model.Marker` | Same pattern |
| `com.google.android.gms.maps.model.MarkerOptions` | `com.amap.api.maps.model.MarkerOptions` | Same builder pattern |
| `com.google.android.gms.maps.model.Polyline` | `com.amap.api.maps.model.Polyline` | Same |
| `com.google.android.gms.maps.model.PolylineOptions` | `com.amap.api.maps.model.PolylineOptions` | Same |
| `com.google.android.gms.maps.model.Polygon` | `com.amap.api.maps.model.Polygon` | Same |
| `com.google.android.gms.maps.model.Circle` | `com.amap.api.maps.model.Circle` | Same |
| `com.google.android.gms.maps.model.CircleOptions` | `com.amap.api.maps.model.CircleOptions` | Same |
| `com.google.android.gms.maps.model.CameraPosition` | `com.amap.api.maps.model.CameraPosition` | Same builder |
| `com.google.android.gms.maps.CameraUpdateFactory` | `com.amap.api.maps.CameraUpdateFactory` | Same factory |
| `com.google.android.gms.maps.model.BitmapDescriptorFactory` | `com.amap.api.maps.model.BitmapDescriptorFactory` | Same |
| `GoogleMap.OnMapClickListener` | `AMap.OnMapClickListener` | Same interface pattern |
| `GoogleMap.OnMarkerClickListener` | `AMap.OnMarkerClickListener` | Same |
| `com.google.android.gms.maps.model.GroundOverlay` | `com.amap.api.maps.model.GroundOverlay` | Same |
**AMap Search/Route (separate SDK):**
| Google Play Services | AMap Services SDK | Notes |
|---|---|---|
| `com.google.android.libraries.places.api.model.Place` | `com.amap.api.services.core.PoiItem` | POI result |
| `com.google.maps.GeocodingApi` | `com.amap.api.services.geocoder.GeocodeSearch` | Geocoding |
| `com.google.maps.DirectionsApi` | `com.amap.api.services.route.RouteSearch` | Route planning |
| `com.google.maps.DistanceMatrixApi` | `com.amap.api.services.route.DistanceSearch` | Distance |
#### Code Migration: Android Map + Marker
```java
// ──── GOOGLE ────
GoogleMap googleMap; // from OnMapReadyCallback
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(35.68, 139.76), 12));
googleMap.addMarker(new MarkerOptions().position(new LatLng(35.68, 139.76)).title("Tokyo"));
// ──── AMAP ────
AMap aMap; // from mapView.getMap()
aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(35.68, 139.76), 12));
aMap.addMarker(new MarkerOptions().position(new LatLng(35.68, 139.76)).title("Tokyo"));
// Nearly identical! Just change import package.
```
#### Code Migration: Android Geocoding
```java
// ──── GOOGLE ────
Geocoder geocoder = new Geocoder(context);
List<Address> results = geocoder.getFromLocationName("Tokyo", 1);
double lat = results.get(0).getLatitude();
// ──── AMAP ────
GeocodeSearch geocodeSearch = new GeocodeSearch(context);
GeocodeQuery query = new GeocodeQuery("Tokyo", "");
geocodeSearch.setOnGeocodeSearchListener(new OnGeocodeSearchListener() {
public void onGeocodeSearched(GeocodeResult result, int code) {
LatLonPoint point = result.getGeocodeAddressList().get(0).getLatLonPoint();
double lat = point.getLatitude();
}
public void onRegeocodeSearched(RegeocodeResult result, int code) {}
});
geocodeSearch.getFromLocationNameAsyn(query);
```
### iOS: Google Maps SDK → AMap iOS SDK
AMap iOS uses `MA` prefix for map classes and `AMap` prefix for search/route models.
#### Class Mapping: Google → AMap iOS
| Google Maps iOS SDK | AMap iOS SDK | Notes |
|---|---|---|
| `GMSMapView` | `MAMapView` | Core map view |
| `GMSMarker` | `MAPointAnnotation` + `MAAnnotationView` | AMap separates data model from view |
| `GMSPolyline` | `MAPolyline` + `MAPolylineRenderer` | AMap separates overlay from renderer |
| `GMSPolygon` | `MAPolygon` + `MAPolygonRenderer` | Same pattern |
| `GMSCircle` | `MACircle` + `MACircleRenderer` | Same pattern |
| `GMSCameraPosition` | `MAMapStatus` | Camera state |
| `GMSCoordinateBounds` | `MACoordinateRegion` | Bounds |
| `CLLocationCoordinate2D` | `CLLocationCoordinate2D` | Same (both use CoreLocation) |
| `GMSGeocoder` | `AMapSearchAPI` + `AMapGeocodeSearchRequest` | Search SDK |
| `GMSPath` | `MAPolyline` coordinates | Different approach |
| `GMSMapViewDelegate` | `MAMapViewDelegate` | Same delegate pattern |
**AMap iOS Search SDK:**
| Google | AMap iOS Search SDK | Notes |
|---|---|---|
| Places SDK `GMSPlacesClient` | `AMapSearchAPI` + `AMapPOIKeywordsSearchRequest` | POI search |
| Directions | `AMapSearchAPI` + `AMapDrivingRouteSearchRequest` | Route |
| Geocoding | `AMapSearchAPI` + `AMapGeocodeSearchRequest` | Geocode |
#### Code Migration: iOS Map + Annotation
```objc
// ──── GOOGLE ────
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:35.68 longitude:139.76 zoom:12];
GMSMapView *mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
GMSMarker *marker = [[GMSMarker alloc] init];
marker.position = CLLocationCoordinate2DMake(35.68, 139.76);
marker.title = @"Tokyo";
marker.map = mapView;
// ──── AMAP ────
MAMapView *mapView = [[MAMapView alloc] initWithFrame:self.view.bounds];
[mapView setCenterCoordinate:CLLocationCoordinate2DMake(35.68, 139.76) animated:NO];
[mapView setZoomLevel:12 animated:NO];
MAPointAnnotation *annotation = [[MAPointAnnotation alloc] init];
annotation.coordinate = CLLocationCoordinate2DMake(35.68, 139.76);
annotation.title = @"Tokyo";
[mapView addAnnotation:annotation];
```
### Non-Mainland SDK / 非中国大陆及港澳台以外地区 SDK
Native mobile SDK for Non-Mainland is **coming soon / 敬请期待**. Non-Mainland mobile developers can currently use the JS API in WebView or call Web Service APIs from native code.
---
## Quick Migration Checklist / 快速迁移清单
1. **Coordinates** — `{lat, lng}` → `[lng, lat]` everywhere (JS API, Web API). Android SDK LatLng stays `(lat, lng)`.
2. **Endpoints** — Use correct endpoints for developer region
3. **Auth** — Replace Google key with AMap key. JS API also needs `securityJsCode`.
4. **`city` param** — Required for Non-Mainland search/geocoding APIs (adcode)
5. **Response parsing** — AMap location is `"lng,lat"` string, not `{lat, lng}` object
6. **Events** — `zoom_changed`→`zoomchange`, `center_changed`→`moveend`
7. **Plugins** — AMap JS API needs `AMap.plugin()` for Geocoder, Driving, PlaceSearch, etc.
8. **Android imports** — Change package from `com.google.android.gms.maps` → `com.amap.api.maps`
9. **iOS classes** — `GMS*` → `MA*`, marker model/view separation
## Reference Files / 参考文件
- **`references/web-api-params.md`** — All 14 APIs: Google request params → AMap request params, Google response fields → AMap response fields, complete code examples
- **`references/js-api-detail.md`** — Full JS API migration: every class method-by-method, overlays, controls, complete before/after HTML pages
- **`references/sdk-migration.md`** — Android & iOS SDK: dependency setup, lifecycle, advanced patterns (clustering, heatmap, custom overlays)
---
## Installation & Updates / 安装与更新
This skill is part of the **[amap-map-agent-skills](https://github.com/AMap-Web/amap-map-agent-skills)** repository, which hosts multiple AMap skills and is continuously updated.
本 Skill 属于 **[amap-map-agent-skills](https://github.com/AMap-Web/amap-map-agent-skills)** 仓库,仓库内包含多个高德地图 Skill,持续更新中。
```bash
# Install or update to the latest version / 安装或更新到最新版本
npx skills add AMap-Web/amap-map-agent-skills
```
FILE:references/sdk-migration.md
# SDK Migration: Google Maps → AMap — Android & iOS
## API Key / 获取 Key
The public Web/JS API keys in the main guide do not cover mobile SDK. To get an SDK key, sign in at [AMap Developer Console](https://lbs.amap.com/) (Chinese site), go to the console, and create your own key — a daily free quota is included. If the quota runs out, retry the next day or contact sales at [AMap Overseas](https://mapsplatform.opnavi.com/) for dedicated capacity.
主文档中的公共 Web/JS API Key 不适用于移动端 SDK。请前往 [高德开发者控制台](https://lbs.amap.com/) 登录后自行创建 Key,每日提供一定免费额度。若额度用尽可次日重试,或访问 [高德海外版官网](https://mapsplatform.opnavi.com/) 联系销售获取专属支持。
## Android SDK: Google → AMap
### Dependencies
```groovy
// ── GOOGLE (build.gradle) ──
implementation 'com.google.android.gms:play-services-maps:18.2.0'
implementation 'com.google.android.gms:play-services-location:21.0.1'
// ── AMAP (build.gradle) ──
implementation 'com.amap.api:3dmap:latest.integration' // Map SDK
implementation 'com.amap.api:search:latest.integration' // Search/Geocode/Route SDK
implementation 'com.amap.api:location:latest.integration' // Location SDK
```
### Package Mapping
| Google Package | AMap Package |
|---|---|
| `com.google.android.gms.maps` | `com.amap.api.maps` |
| `com.google.android.gms.maps.model` | `com.amap.api.maps.model` |
| `com.google.android.gms.location` | `com.amap.api.location` |
| `com.google.android.libraries.places.api` | `com.amap.api.services.poisearch` |
| `com.google.maps` (server SDK) | `com.amap.api.services` |
### Core Class Mapping
| Google Class | AMap Class |
|---|---|
| `GoogleMap` | `AMap` |
| `MapView` | `MapView` |
| `SupportMapFragment` | `SupportMapFragment` |
| `OnMapReadyCallback` | `OnMapReadyCallback` |
| `LatLng(lat, lng)` | `LatLng(lat, lng)` — **Same order on Android!** |
| `LatLngBounds` | `LatLngBounds` |
| `CameraPosition` | `CameraPosition` |
| `CameraPosition.Builder` | `CameraPosition.Builder` |
| `CameraUpdateFactory` | `CameraUpdateFactory` |
| `CameraUpdate` | `CameraUpdate` |
| `BitmapDescriptorFactory` | `BitmapDescriptorFactory` |
| `Marker` | `Marker` |
| `MarkerOptions` | `MarkerOptions` |
| `Polyline` | `Polyline` |
| `PolylineOptions` | `PolylineOptions` |
| `Polygon` | `Polygon` |
| `PolygonOptions` | `PolygonOptions` |
| `Circle` | `Circle` |
| `CircleOptions` | `CircleOptions` |
| `GroundOverlay` | `GroundOverlay` |
| `TileOverlay` | `TileOverlay` |
### Listener Mapping
| Google Listener | AMap Listener |
|---|---|
| `GoogleMap.OnMapClickListener` | `AMap.OnMapClickListener` |
| `GoogleMap.OnMarkerClickListener` | `AMap.OnMarkerClickListener` |
| `GoogleMap.OnCameraIdleListener` | `AMap.OnCameraChangeListener` |
| `GoogleMap.OnMyLocationClickListener` | `AMap.OnMyLocationChangeListener` |
| `GoogleMap.InfoWindowAdapter` | `AMap.InfoWindowAdapter` |
### Search/Route Class Mapping
| Google | AMap | Notes |
|---|---|---|
| `Geocoder` | `GeocodeSearch` | `com.amap.api.services.geocoder` |
| `Address` | `GeocodeAddress` / `RegeocodeAddress` | — |
| *(Directions SDK)* | `RouteSearch` | `com.amap.api.services.route` |
| *(Directions result)* | `DriveRouteResult` / `WalkRouteResult` / `BusRouteResult` | Per mode |
| `PlacesClient` | `PoiSearch` | `com.amap.api.services.poisearch` |
| `Place` | `PoiItem` | — |
| *(Distance Matrix)* | `DistanceSearch` | `com.amap.api.services.route` |
### Code: Map Init
```java
// ── GOOGLE ──
public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback {
private GoogleMap mMap;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(35.68, 139.76), 12));
}
}
// ── AMAP ──
public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback {
private AMap aMap;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
public void onMapReady(AMap map) {
aMap = map;
aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(35.68, 139.76), 12));
// Nearly identical! Just change GoogleMap→AMap, change imports.
}
}
```
### Code: Markers
```java
// ── GOOGLE ──
mMap.addMarker(new MarkerOptions()
.position(new LatLng(35.68, 139.76))
.title("Tokyo")
.snippet("Capital of Japan")
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)));
// ── AMAP ──
aMap.addMarker(new MarkerOptions()
.position(new LatLng(35.68, 139.76))
.title("Tokyo")
.snippet("Capital of Japan")
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)));
// Identical code — just change imports!
```
### Code: Polyline
```java
// ── GOOGLE ──
mMap.addPolyline(new PolylineOptions()
.add(new LatLng(35.68, 139.76), new LatLng(35.65, 139.69))
.width(5).color(Color.RED));
// ── AMAP ──
aMap.addPolyline(new PolylineOptions()
.add(new LatLng(35.68, 139.76), new LatLng(35.65, 139.69))
.width(5).color(Color.RED));
// Identical!
```
### Code: Geocoding
```java
// ── GOOGLE ──
Geocoder geocoder = new Geocoder(context, Locale.getDefault());
List<Address> addresses = geocoder.getFromLocationName("Tokyo", 1);
LatLng location = new LatLng(addresses.get(0).getLatitude(), addresses.get(0).getLongitude());
// ── AMAP ── (async pattern)
GeocodeSearch geocodeSearch = new GeocodeSearch(context);
geocodeSearch.setOnGeocodeSearchListener(new GeocodeSearch.OnGeocodeSearchListener() {
public void onGeocodeSearched(GeocodeResult result, int rCode) {
if (rCode == 1000) {
GeocodeAddress addr = result.getGeocodeAddressList().get(0);
LatLonPoint point = addr.getLatLonPoint();
LatLng location = new LatLng(point.getLatitude(), point.getLongitude());
}
}
public void onRegeocodeSearched(RegeocodeResult result, int rCode) {}
});
GeocodeQuery query = new GeocodeQuery("Tokyo", "");
geocodeSearch.getFromLocationNameAsyn(query);
```
### Code: Route Search
```java
// ── GOOGLE ── (typically uses REST API or Directions SDK)
// Most Android apps call the Directions REST API directly
// ── AMAP ──
RouteSearch routeSearch = new RouteSearch(context);
routeSearch.setRouteSearchListener(new RouteSearch.OnRouteSearchListener() {
public void onDriveRouteSearched(DriveRouteResult result, int errorCode) {
if (errorCode == 1000) {
DrivePath path = result.getPaths().get(0);
float distance = path.getDistance(); // meters
long duration = path.getDuration(); // seconds
}
}
// ... other mode callbacks
});
RouteSearch.FromAndTo fromAndTo = new RouteSearch.FromAndTo(
new LatLonPoint(35.68, 139.76), // start
new LatLonPoint(35.65, 139.69) // end
);
RouteSearch.DriveRouteQuery query = new RouteSearch.DriveRouteQuery(fromAndTo, 0, null, null, "");
routeSearch.calculateDriveRouteAsyn(query);
```
### Android Lifecycle
AMap MapView requires lifecycle calls (same pattern as Google):
```java
protected void onResume() { super.onResume(); mapView.onResume(); }
protected void onPause() { super.onPause(); mapView.onPause(); }
protected void onDestroy() { super.onDestroy(); mapView.onDestroy(); }
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
```
---
## iOS SDK: Google → AMap
### Dependencies
```ruby
# ── GOOGLE (Podfile) ──
pod 'GoogleMaps', '~> 8.0'
pod 'GooglePlaces', '~> 8.0'
# ── AMAP (Podfile) ──
pod 'AMap3DMap' # 3D Map SDK
pod 'AMapSearch' # Search/Geocode/Route
pod 'AMapLocation' # Location
```
### Class Mapping
| Google Class | AMap Class | Notes |
|---|---|---|
| `GMSMapView` | `MAMapView` | Core map view |
| `GMSMarker` | `MAPointAnnotation` | Data model only |
| *(marker view)* | `MAAnnotationView` / `MAPinAnnotationView` | AMap separates model and view |
| `GMSPolyline` | `MAPolyline` | Data model |
| *(polyline render)* | `MAPolylineRenderer` | Separate renderer |
| `GMSPolygon` | `MAPolygon` + `MAPolygonRenderer` | — |
| `GMSCircle` | `MACircle` + `MACircleRenderer` | — |
| `GMSCameraPosition` | `MAMapStatus` | Camera |
| `GMSCoordinateBounds` | `MACoordinateRegion` | Bounds |
| `GMSGeocoder` | `AMapSearchAPI` | Unified search API |
| `GMSPlacesClient` | `AMapSearchAPI` | Unified search API |
| `GMSMapViewDelegate` | `MAMapViewDelegate` | Delegate |
| `CLLocationCoordinate2D` | `CLLocationCoordinate2D` | Same (CoreLocation) |
### Code: Map Init
```objc
// ── GOOGLE ──
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:35.68 longitude:139.76 zoom:12];
GMSMapView *mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
self.view = mapView;
// ── AMAP ──
MAMapView *mapView = [[MAMapView alloc] initWithFrame:self.view.bounds];
mapView.delegate = self;
[mapView setCenterCoordinate:CLLocationCoordinate2DMake(35.68, 139.76) animated:NO];
[mapView setZoomLevel:12 animated:NO];
[self.view addSubview:mapView];
```
### Code: Markers / Annotations
```objc
// ── GOOGLE ──
GMSMarker *marker = [[GMSMarker alloc] init];
marker.position = CLLocationCoordinate2DMake(35.68, 139.76);
marker.title = @"Tokyo";
marker.snippet = @"Capital of Japan";
marker.map = mapView;
// ── AMAP ──
MAPointAnnotation *annotation = [[MAPointAnnotation alloc] init];
annotation.coordinate = CLLocationCoordinate2DMake(35.68, 139.76);
annotation.title = @"Tokyo";
annotation.subtitle = @"Capital of Japan";
[mapView addAnnotation:annotation];
// Customize view via delegate:
- (MAAnnotationView *)mapView:(MAMapView *)mapView viewForAnnotation:(id<MAAnnotation>)annotation {
MAPinAnnotationView *pinView = (MAPinAnnotationView *)[mapView
dequeueReusableAnnotationViewWithIdentifier:@"pin"];
if (!pinView) {
pinView = [[MAPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"pin"];
pinView.canShowCallout = YES;
}
return pinView;
}
```
### Code: Polyline
```objc
// ── GOOGLE ──
GMSMutablePath *path = [GMSMutablePath path];
[path addCoordinate:CLLocationCoordinate2DMake(35.68, 139.76)];
[path addCoordinate:CLLocationCoordinate2DMake(35.65, 139.69)];
GMSPolyline *polyline = [GMSPolyline polylineWithPath:path];
polyline.strokeColor = [UIColor redColor];
polyline.strokeWidth = 3;
polyline.map = mapView;
// ── AMAP ──
CLLocationCoordinate2D coords[2] = {
CLLocationCoordinate2DMake(35.68, 139.76),
CLLocationCoordinate2DMake(35.65, 139.69)
};
MAPolyline *polyline = [MAPolyline polylineWithCoordinates:coords count:2];
[mapView addOverlay:polyline];
// Customize via delegate:
- (MAOverlayRenderer *)mapView:(MAMapView *)mapView rendererForOverlay:(id<MAOverlay>)overlay {
if ([overlay isKindOfClass:[MAPolyline class]]) {
MAPolylineRenderer *renderer = [[MAPolylineRenderer alloc] initWithPolyline:overlay];
renderer.strokeColor = [UIColor redColor];
renderer.lineWidth = 3;
return renderer;
}
return nil;
}
```
### Code: Geocoding (Forward)
```objc
// ── GOOGLE ──
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:@"Tokyo" completionHandler:^(NSArray<CLPlacemark *> *placemarks, NSError *err) {
CLLocationCoordinate2D coord = placemarks.firstObject.location.coordinate;
}];
// ── AMAP ──
AMapSearchAPI *search = [[AMapSearchAPI alloc] init];
search.delegate = self;
AMapGeocodeSearchRequest *req = [[AMapGeocodeSearchRequest alloc] init];
req.address = @"Tokyo";
[search AMapGeocodeSearch:req];
// Delegate callback:
- (void)onGeocodeSearchDone:(AMapGeocodeSearchRequest *)request response:(AMapGeocodeSearchResponse *)response {
AMapGeocode *geo = response.geocodes.firstObject;
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(geo.location.latitude, geo.location.longitude);
}
```
### Code: Geocoding (Reverse)
```objc
// ── GOOGLE ──
GMSGeocoder *geocoder = [GMSGeocoder geocoder];
[geocoder reverseGeocodeCoordinate:coord completionHandler:^(GMSReverseGeocodeResponse *resp, NSError *err) {
GMSAddress *address = resp.firstResult;
}];
// ── AMAP ──
AMapSearchAPI *search = [[AMapSearchAPI alloc] init];
search.delegate = self;
AMapReGeocodeSearchRequest *req = [[AMapReGeocodeSearchRequest alloc] init];
req.location = [AMapGeoPoint locationWithLatitude:35.68 longitude:139.76];
[search AMapReGoecodeSearch:req];
// Delegate callback:
- (void)onReGeocodeSearchDone:(AMapReGeocodeSearchRequest *)request response:(AMapReGeocodeSearchResponse *)response {
NSString *address = response.regeocode.formattedAddress;
}
```
### iOS Key Difference: Model/View Separation
Google iOS SDK (`GMSMarker`, `GMSPolyline`, etc.) combines data and visual representation in one object. AMap iOS SDK separates them:
- **Data model:** `MAPointAnnotation`, `MAPolyline`, `MAPolygon`, `MACircle`
- **Visual renderer:** `MAAnnotationView`, `MAPolylineRenderer`, `MAPolygonRenderer`, `MACircleRenderer`
You configure visuals via `MAMapViewDelegate` methods, similar to `UITableViewDelegate` pattern. This is more code but gives finer control.
---
## Non-Mainland SDK
Native mobile SDK for Non-Mainland (excl. HK/MO/TW) regions is **coming soon / 敬请期待**. Current options for Non-Mainland mobile:
1. **WebView + JS API** — Use AMap JS API in a WebView for map rendering
2. **Web Service API** — Call REST APIs from native code for geocoding, search, routing
3. **Hybrid approach** — Native UI + WebView map + REST APIs for services
FILE:references/web-api-params.md
# Web Service API: Google → AMap Complete Parameter & Response Mapping
Every API below shows: Google request → AMap request (param-by-param), Google response → AMap response (field-by-field), and working code.
AMap Non-Mainland domain: `https://sg-restapi.opnavi.com` | Mainland: `https://restapi.amap.com`
Google domain: `https://maps.googleapis.com`
---
## 1. Autocomplete / Places Autocomplete → 输入提示
**Google:** `GET /maps/api/place/autocomplete/json`
**AMap:** `GET /v3/assistant/inputtips`
### Request Params
| Google Param | AMap Param | Notes |
|---|---|---|
| `key` | `key` | Swap key value |
| `input` | `keywords` | Rename |
| `location` (lat,lng) | `location` (lng,lat) | Reversed |
| `radius` | *(use city/adcode)* | AMap uses city-based scoping |
| `types` | `type` | AMap uses its own POI typecodes |
| `language` | `langCode` | zh/en/ja/ko etc. |
| — | `city` | **Required for Non-Mainland**, adcode |
### Response Fields
| Google Field | AMap Field | Notes |
|---|---|---|
| `predictions[]` | `tips[]` | Array name differs |
| `prediction.description` | `tip.name` + `tip.district` | Combine for full description |
| `prediction.place_id` | `tip.id` | Non-Mainland IDs start with `P` |
| `prediction.structured_formatting.main_text` | `tip.name` | Direct |
| — | `tip.location` | `"lng,lat"` string |
| — | `tip.adcode` | Region code |
### Example
```javascript
// Google
`https://maps.googleapis.com/maps/api/place/autocomplete/json?input=starbucks&key=G_KEY`
// AMap (Non-Mainland)
`https://sg-restapi.opnavi.com/v3/assistant/inputtips?keywords=starbucks&city=840000000&key=40ffec9172a0dd65b7e224bb252b7e0b&appname=amap-map-google-maps-migration`
```
---
## 2. Text Search / Keyword Search → 关键字搜索
**Google:** `GET /maps/api/place/textsearch/json`
**AMap:** `GET /v3/place/text`
### Request Params
| Google Param | AMap Param | Notes |
|---|---|---|
| `key` | `key` | — |
| `query` | `keywords` | Rename |
| `location` (lat,lng) | *(not used)* | AMap uses `city` scoping |
| `radius` | *(not used)* | — |
| `type` | `types` | AMap POI typecodes, `\|` separated |
| `pagetoken` | `page` + `offset` | AMap: `page`=page number, `offset`=per page (max 50) |
| `language` | `langCode` | — |
| — | `city` | **Required for Non-Mainland** |
| — | `extensions` | `base` or `all` |
### Response Fields
| Google Field | AMap Field | Notes |
|---|---|---|
| `results[]` | `pois[]` | — |
| `result.name` | `poi.name` | Direct |
| `result.formatted_address` | `poi.address` | Direct |
| `result.geometry.location.lat` | `poi.location.split(',')[1]` | String parse |
| `result.geometry.location.lng` | `poi.location.split(',')[0]` | String parse |
| `result.place_id` | `poi.id` | `P`-prefix Non-Mainland |
| `result.types[]` | `poi.type` / `poi.typecode` | Different classification |
| `result.rating` | *(not available)* | — |
| `result.opening_hours` | *(not available)* | — |
| — | `poi.tel` | Phone number |
| — | `poi.pname` / `poi.cityname` / `poi.adname` | Region hierarchy |
---
## 3. Nearby Search → 周边搜索
**Google:** `GET /maps/api/place/nearbysearch/json`
**AMap:** `GET /v3/place/around`
### Request Params
| Google Param | AMap Param | Notes |
|---|---|---|
| `key` | `key` | — |
| `location` (lat,lng) | `location` (lng,lat) | **Reversed** |
| `radius` (meters) | `radius` (meters, 0-50000) | Same unit |
| `keyword` | `keywords` | Rename |
| `type` | `types` | AMap typecodes |
| `pagetoken` | `page` + `offset` | — |
### Response Fields
Same as Keyword Search (#2). Plus `poi.distance` (meters from center) is populated.
---
## 4. Place Details / ID Search → ID搜索
**Google:** `GET /maps/api/place/details/json`
**AMap:** `GET /v3/place/detail`
### Request Params
| Google Param | AMap Param | Notes |
|---|---|---|
| `key` | `key` | — |
| `place_id` | `id` | AMap Non-Mainland IDs: `P0JAK55X50` format |
| `fields` | *(not needed)* | AMap returns full POI |
| `language` | *(not available)* | — |
### Response Fields
| Google Field | AMap Field | Notes |
|---|---|---|
| `result.name` | `pois[0].name` | AMap wraps in array |
| `result.formatted_address` | `pois[0].address` | — |
| `result.geometry.location` | `pois[0].location` | `"lng,lat"` string |
| `result.formatted_phone_number` | `pois[0].tel` | — |
| `result.types` | `pois[0].type` | — |
| `result.rating` | *(not available)* | — |
| `result.reviews` | *(not available)* | — |
---
## 5. Polygon Search → 多边形搜索
**Google:** *(No direct equivalent — Google requires Nearby Search with custom client-side filtering)*
**AMap:** `GET /v3/place/polygon`
AMap-specific. `polygon` param: `lng,lat|lng,lat|...` (first & last must match, or 2 corners for rectangle). Plus `keywords` or `types`.
---
## 6. Geocoding → 地理编码
**Google:** `GET /maps/api/geocode/json` (with `address=`)
**AMap:** `GET /v3/geocode/geo`
### Request Params
| Google Param | AMap Param | Notes |
|---|---|---|
| `key` | `key` | — |
| `address` | `address` | Non-Mainland: low-level first ("9 Madison Ave, NY, USA") |
| `components` | `city` | AMap uses adcode instead of component filtering |
| `language` | *(not available)* | — |
### Response Fields
| Google Field | AMap Field | Notes |
|---|---|---|
| `results[]` | `geocodes[]` | — |
| `result.geometry.location.lat` | `geocode.location.split(',')[1]` | String parse |
| `result.geometry.location.lng` | `geocode.location.split(',')[0]` | String parse |
| `result.formatted_address` | Concat: `country+province+city+district+street+number` | AMap returns flat fields |
| `result.address_components[].long_name` | `geocode.country/province/city/district/street/number` | Flat, not array |
| `result.place_id` | *(not returned)* | — |
---
## 7. Reverse Geocoding → 逆地理编码
**Google:** `GET /maps/api/geocode/json` (with `latlng=`)
**AMap:** `GET /v3/geocode/regeo`
### Request Params
| Google Param | AMap Param | Notes |
|---|---|---|
| `key` | `key` | — |
| `latlng` (lat,lng) | `location` (lng,lat) | **Reversed** |
| `result_type` | `poitype` | Filter POI types (requires `extensions=all`) |
| `language` | `langCode` | 20+ languages |
| — | `radius` | 0-3000m, default 1000 |
| — | `extensions` | `base` or `all` (all includes nearby POIs, roads) |
### Response Fields
| Google Field | AMap Field | Notes |
|---|---|---|
| `results[0].formatted_address` | `regeocode.formatted_address` | Direct |
| `results[0].address_components[]` | `regeocode.addressComponent` | Object with country/province/city/district/township |
| `results[0].geometry.location` | Request `location` param | Not re-returned |
| — | `regeocode.pois[]` | Nearby POIs (when extensions=all) |
---
## 8. Geolocation → 网络定位
**Google:** `POST https://www.googleapis.com/geolocation/v1/geolocate`
**AMap Non-Mainland:** `GET http://sg-apilocate.opnavi.com/position` ⚠️ HTTP only — use HTTPS in production where supported / 生产环境建议使用 HTTPS
**AMap Mainland:** `GET https://restapi.amap.com/v3/position`
| Google Param | AMap Param | Notes |
|---|---|---|
| `wifiAccessPoints[]` | `macs` | WiFi MAC addresses |
| `cellTowers[]` | `bts` / `nearbts` | Cell tower info |
| — | `accesstype` | 0=mobile, 1=wifi |
| — | `imei` | Device IMEI |
Both return lat/lng position. AMap for IoT hardware positioning.
---
## 9. Driving Directions → 驾车路径规划
**Google:** `GET /maps/api/directions/json` (mode=driving)
**AMap:** `GET /v3/direction/driving`
### Request Params
| Google Param | AMap Param | Notes |
|---|---|---|
| `key` | `key` | — |
| `origin` (lat,lng) | `origin` (lng,lat) | **Reversed** |
| `destination` (lat,lng) | `destination` (lng,lat) | **Reversed** |
| `waypoints` (lat,lng\|...) | `waypoints` (lng,lat;...) | Reversed + `;` separator, max 16 |
| `avoid=tolls` | `strategy=14` | Strategy number |
| `avoid=highways` | `strategy=13` | Strategy number |
| `alternatives=true` | `strategy=10` (or 11-20) | Multi-route strategies |
| `language` | `langCode` | zh / en |
| — | `origin_id` / `destination_id` | POI ID for accuracy |
### Response Fields
| Google Field | AMap Field | Notes |
|---|---|---|
| `routes[].legs[].distance.value` | `route.paths[].distance` | Meters |
| `routes[].legs[].duration.value` | `route.paths[].duration` | Seconds |
| `routes[].legs[].steps[]` | `route.paths[].steps[]` | Turn-by-turn |
| `step.html_instructions` | `step.instruction` | Instruction text |
| `step.distance.value` | `step.distance` | Meters |
| `step.polyline.points` | `step.polyline` | Encoded polyline |
---
## 10. Walking Directions → 步行路径规划
**Google:** `GET /maps/api/directions/json` (mode=walking)
**AMap:** `GET /v3/direction/walking`
Same param pattern as Driving (#9) but without `strategy`/`waypoints`. Response structure matches driving.
---
## 11. Transit Directions → 公交路径规划
**Google:** `GET /maps/api/directions/json` (mode=transit)
**AMap Non-Mainland:** `GET /v5/direction/transit/integrated/abroad`
**AMap Mainland:** `GET /v3/direction/transit/integrated`
### Extra AMap Params (vs Google)
| Google Param | AMap Param | Notes |
|---|---|---|
| `departure_time` | `date` + `time` | AMap uses separate date (`YYYY-MM-DD`) and time (`HH:MM`) |
| `transit_mode` | `strategy` | 0=fastest, 1=cheapest, 2=fewest transfers, 3=least walking, 5=no subway |
| — | `city` / `cityd` | Required for cross-city transit |
| — | `nightflag` | 0=no night bus, 1=include |
Non-Mainland transit coverage: USA, Japan, South Korea, UK, Singapore, Canada + 11 more countries.
---
## 12. Distance Matrix → 矩阵距离测量
**Google:** `GET /maps/api/distancematrix/json`
**AMap:** `POST /v5/distance/matrix`
### Request Params
| Google Param | AMap Param | Notes |
|---|---|---|
| `key` | `key` | — |
| `origins` (lat,lng\|lat,lng) | `origins` (lng,lat;lng,lat) | **Reversed + `;` separator**, max 25 |
| `destinations` (lat,lng\|lat,lng) | `destinations` (lng,lat;lng,lat) | **Reversed + `;` separator**, max 25 |
| `mode` | `travelMode` | `Drive` (default) |
| `departure_time` | `departureTime` | Unix timestamp (seconds), future only, max 7 days |
| — | `routingPreference` | 1=speed priority |
### Response Fields
| Google Field | AMap Field | Notes |
|---|---|---|
| `rows[i].elements[j].distance.value` | `routes[].route[].distanceMeters` | Meters |
| `rows[i].elements[j].duration.value` | `routes[].route[].duration` | Seconds |
| `rows[i].elements[j].status` | `routes[].route[].status` | 0=OK, 1=distance limit, 2=timeout |
| — | `routes[].route[].originIndex` | Origin index (1-25) |
| — | `routes[].route[].destinationIndex` | Destination index (1-25) |
---
## 13. Admin Division → 行政区划查询
**Google:** *(No equivalent)*
**AMap Non-Mainland:** `GET /v5/district/global`
**AMap Mainland:** `GET /v3/config/district`
Params: `keywords` (region name or adcode), `subdistrict` (0,1,2... sub-levels), `langCode`, `page`, `offset`.
Response: `districts[]` → `{adcode, name, center, level, districts[]}`. Levels: 1=country, 2=province/state, 3=city, 4=district.
---
## 14. Time Zone → 时区
**Google:** `GET /maps/api/timezone/json`
**AMap:** `GET /v5/timezone`
### Request Params
| Google Param | AMap Param | Notes |
|---|---|---|
| `key` | `key` | — |
| `location` (lat,lng) | `location` (lng,lat) | **Reversed** |
| `timestamp` (Unix seconds) | `time` (Unix when time_type=1) | Same value |
| — | `time_type` | 1=UTC input (default), 2=local time input |
### Response Fields
| Google Field | AMap Field | Notes |
|---|---|---|
| `timeZoneId` | `time_zone_id` | e.g. `America/New_York` |
| `timeZoneName` | *(not returned)* | — |
| `rawOffset` (seconds) | `rawoffset` (seconds) | Same |
| `dstOffset` (seconds) | `dstoffset` (seconds) | Same |
| — | `time` | Converted time output |
FILE:references/js-api-detail.md
# JS API Migration: Google Maps → AMap — Complete Reference
Self-contained reference. No external links needed — all migration info is here.
---
## Setup: Google → AMap
```html
<!-- ══ GOOGLE ══ -->
<script src="https://maps.googleapis.com/maps/api/js?key=GOOGLE_KEY&callback=initMap" async defer></script>
<!-- ══ AMAP (Non-Mainland) ══ -->
<script>window._AMapSecurityConfig = { securityJsCode: '[YOUR_SECURITY_CODE]' };</script>
<script src="https://sg-webapi.opnavi.com/maps?v=2.0&key=b87b3d194a024295b1b17be020659457&appname=amap-map-google-maps-migration"></script>
<!-- ══ AMAP (Mainland) ══ -->
<script>window._AMapSecurityConfig = { securityJsCode: '[YOUR_SECURITY_CODE]' };</script>
<script src="https://webapi.amap.com/maps?v=2.0&key=b87b3d194a024295b1b17be020659457&appname=amap-map-google-maps-migration"></script>
```
AMap requires dual auth: `securityJsCode` BEFORE CDN loads + `key` in CDN URL. Google needs only one key.
---
## AMap.Map (replaces google.maps.Map)
### Constructor
```javascript
// Google
const map = new google.maps.Map(document.getElementById('map'), {
center: { lat: 35.68, lng: 139.76 },
zoom: 12,
mapTypeId: 'roadmap'
});
// AMap
const map = new AMap.Map('map', { // string ID, not element
center: [139.76, 35.68], // [lng, lat] REVERSED
zoom: 12,
viewMode: '2D', // or '3D'
mapStyle: 'amap://styles/normal' // normal/dark/light/fresh
});
```
### Options Mapping
| Google Option | AMap Option | Notes |
|---|---|---|
| `center: {lat, lng}` | `center: [lng, lat]` | Reversed |
| `zoom` | `zoom` | Same (2-20) |
| `mapTypeId: 'roadmap'` | `mapStyle: 'amap://styles/normal'` | Different system |
| `mapTypeId: 'satellite'` | `layers: [new AMap.TileLayer.Satellite()]` | Layer-based |
| `tilt` | `pitch` | 3D tilt (0-83) |
| `heading` | `rotation` | 0-360 |
| *(no equivalent)* | `viewMode: '3D'` | Enable 3D |
| *(no equivalent)* | `features: ['bg','road','building','point']` | Toggle features |
### Methods Mapping
| Google Method | AMap Method | Notes |
|---|---|---|
| `map.setCenter({lat,lng})` | `map.setCenter([lng,lat])` | Reversed |
| `map.getCenter()` | `map.getCenter()` | Returns LngLat |
| `map.setZoom(n)` | `map.setZoom(n)` | Same |
| `map.getZoom()` | `map.getZoom()` | Same |
| `map.panTo({lat,lng})` | `map.panTo([lng,lat])` | Reversed |
| `map.fitBounds(bounds)` | `map.setBounds(bounds)` | Different name |
| `map.getBounds()` | `map.getBounds()` | Same |
| *(no equivalent)* | `map.setZoomAndCenter(zoom,[lng,lat])` | Set both |
| *(no equivalent)* | `map.add(overlay)` | Add overlay |
| *(no equivalent)* | `map.remove(overlay)` | Remove overlay |
| *(no equivalent)* | `map.clearMap()` | Clear all overlays |
| *(no equivalent)* | `map.destroy()` | Destroy instance |
---
## AMap.Marker (replaces google.maps.Marker)
### Constructor
```javascript
// Google
const marker = new google.maps.Marker({
position: { lat: 35.68, lng: 139.76 },
map: map,
title: 'Tokyo',
icon: 'icon.png'
});
marker.setMap(null); // remove
// AMap
const marker = new AMap.Marker({
position: [139.76, 35.68], // [lng, lat] REVERSED
map: map,
title: 'Tokyo',
icon: 'icon.png' // or AMap.Icon instance
});
marker.setMap(null); // same removal pattern
// or: map.remove(marker);
```
### Options Mapping
| Google Option | AMap Option | Notes |
|---|---|---|
| `position: {lat,lng}` | `position: [lng,lat]` | Reversed |
| `map` | `map` | Same |
| `title` | `title` | Same |
| `icon: 'url'` | `icon: 'url'` or `new AMap.Icon(opts)` | Same or richer |
| `label: {text}` | `label: {content, offset, direction}` | Richer |
| `draggable` | `draggable` | Same |
| `visible` | `visible` | Same |
| *(no equivalent)* | `content: '<div>...'` | Custom HTML replaces icon |
| *(no equivalent)* | `anchor: 'center'` | Anchor point |
---
## AMap.InfoWindow (replaces google.maps.InfoWindow)
```javascript
// Google
const iw = new google.maps.InfoWindow({ content: '<h3>Title</h3>' });
marker.addListener('click', () => iw.open(map, marker));
// AMap
const iw = new AMap.InfoWindow({
content: '<h3>Title</h3>',
offset: new AMap.Pixel(0, -30)
});
marker.on('click', () => iw.open(map, marker.getPosition()));
```
**Key difference:** Google's `open(map, marker)` takes marker. AMap's `open(map, position)` takes LngLat position.
---
## Events: Google → AMap
### Syntax
```javascript
// Google — verbose
google.maps.event.addListener(map, 'click', handler);
google.maps.event.removeListener(listenerRef);
// AMap — simple
map.on('click', handler);
map.off('click', handler);
```
### Event Name Mapping
| Google Event | AMap Event |
|---|---|
| `'click'` | `'click'` |
| `'dblclick'` | `'dblclick'` |
| `'rightclick'` | `'rightclick'` |
| `'mousemove'` | `'mousemove'` |
| `'mouseout'` | `'mouseout'` |
| `'mouseover'` | `'mouseover'` |
| `'center_changed'` | `'moveend'` |
| `'zoom_changed'` | `'zoomchange'` |
| `'bounds_changed'` | `'moveend'` |
| `'dragstart'` | `'dragstart'` |
| `'drag'` | `'dragging'` |
| `'dragend'` | `'dragend'` |
| `'idle'` | `'complete'` |
| `'tilesloaded'` | `'complete'` |
| `'resize'` | `'resize'` |
### Event Object
```javascript
// Google
map.addListener('click', (e) => {
console.log(e.latLng.lat(), e.latLng.lng()); // methods
});
// AMap
map.on('click', (e) => {
console.log(e.lnglat.getLat(), e.lnglat.getLng()); // methods
// or: e.lnglat.lat, e.lnglat.lng // properties
});
```
---
## Overlays: Google → AMap
### Polyline
```javascript
// Google
new google.maps.Polyline({
path: [{lat:35.68,lng:139.76}, {lat:35.65,lng:139.69}],
strokeColor: '#FF0000', strokeWeight: 2, map: map
});
// AMap
new AMap.Polyline({
path: [[139.76,35.68], [139.69,35.65]], // [lng,lat] arrays
strokeColor: '#FF0000', strokeWeight: 2, map: map
});
```
### Polygon
```javascript
// Google
new google.maps.Polygon({
paths: [{lat:35.68,lng:139.76}, {lat:35.65,lng:139.69}, {lat:35.66,lng:139.72}],
fillColor: '#FF0000', fillOpacity: 0.35, map: map
});
// AMap — note: "path" singular, not "paths"
new AMap.Polygon({
path: [[139.76,35.68], [139.69,35.65], [139.72,35.66]],
fillColor: '#FF0000', fillOpacity: 0.35, map: map
});
```
### Circle
```javascript
// Google
new google.maps.Circle({ center: {lat:35.68,lng:139.76}, radius: 1000, map: map });
// AMap
new AMap.Circle({ center: [139.76,35.68], radius: 1000, map: map });
```
---
## Plugins: Google → AMap
Google loads all services with the main script. AMap requires explicit plugin loading.
```javascript
AMap.plugin(['AMap.Geocoder','AMap.Driving','AMap.Walking','AMap.Transfer',
'AMap.PlaceSearch','AMap.Autocomplete','AMap.Scale','AMap.ToolBar',
'AMap.ControlBar','AMap.MapType','AMap.HeatMap','AMap.MarkerCluster'], function() {
// All constructors now available
});
```
### Geocoder: Google → AMap
```javascript
// Google
const geocoder = new google.maps.Geocoder();
geocoder.geocode({ address: 'Tokyo' }, (results, status) => {
if (status === 'OK') {
const loc = results[0].geometry.location; // LatLng object
}
});
// AMap
AMap.plugin('AMap.Geocoder', () => {
const geocoder = new AMap.Geocoder();
geocoder.getLocation('Tokyo', (status, result) => {
if (status === 'complete') {
const loc = result.geocodes[0].location; // LngLat object
}
});
});
```
### Driving Directions: Google → AMap
```javascript
// Google
const svc = new google.maps.DirectionsService();
svc.route({
origin: {lat:35.68, lng:139.76},
destination: {lat:35.65, lng:139.69},
travelMode: 'DRIVING'
}, (result, status) => {
// result.routes[0].legs[0].distance
});
// AMap
AMap.plugin('AMap.Driving', () => {
const driving = new AMap.Driving({ map: map });
driving.search(
new AMap.LngLat(139.76, 35.68), // origin [lng, lat]
new AMap.LngLat(139.69, 35.65), // destination
(status, result) => {
// result.routes[0].distance
}
);
});
```
### Place Search: Google → AMap
```javascript
// Google
const svc = new google.maps.places.PlacesService(map);
svc.textSearch({ query: 'restaurants' }, (results, status) => {
results.forEach(r => console.log(r.name, r.geometry.location));
});
// AMap
AMap.plugin('AMap.PlaceSearch', () => {
const ps = new AMap.PlaceSearch({ map: map, pageSize: 10 });
ps.search('restaurants', (status, result) => {
result.poiList.pois.forEach(p => console.log(p.name, p.location));
});
});
```
### Autocomplete: Google → AMap
```javascript
// Google
const ac = new google.maps.places.Autocomplete(document.getElementById('input'));
ac.addListener('place_changed', () => { const place = ac.getPlace(); });
// AMap
AMap.plugin('AMap.Autocomplete', () => {
const ac = new AMap.Autocomplete({ input: 'input' }); // element ID string
ac.on('select', (e) => { const poi = e.poi; });
});
```
---
## Controls: Google → AMap
```javascript
// Google — declarative options
map.setOptions({ zoomControl: true, mapTypeControl: true, scaleControl: true });
// AMap — plugins
AMap.plugin(['AMap.Scale','AMap.ToolBar','AMap.ControlBar','AMap.MapType'], () => {
map.addControl(new AMap.Scale()); // Scale bar
map.addControl(new AMap.ToolBar()); // Zoom + pan
map.addControl(new AMap.ControlBar()); // 3D rotation
map.addControl(new AMap.MapType()); // Map type switch
});
```
---
## Complete Before/After Example
### Google Maps (Before)
```html
<!DOCTYPE html>
<html>
<head>
<script src="https://maps.googleapis.com/maps/api/js?key=GOOGLE_KEY"></script>
</head>
<body>
<div id="map" style="width:100%;height:400px;"></div>
<script>
const map = new google.maps.Map(document.getElementById('map'), {
center: { lat: 1.3521, lng: 103.8198 }, zoom: 13
});
const marker = new google.maps.Marker({
position: { lat: 1.3521, lng: 103.8198 }, map: map, title: 'Singapore'
});
const iw = new google.maps.InfoWindow({ content: '<h3>Singapore</h3>' });
marker.addListener('click', () => iw.open(map, marker));
map.addListener('click', (e) => {
console.log(e.latLng.lat(), e.latLng.lng());
});
</script>
</body>
</html>
```
### AMap (After — Non-Mainland)
```html
<!DOCTYPE html>
<html>
<head>
<script>window._AMapSecurityConfig = { securityJsCode: '[YOUR_SECURITY_CODE]' };</script>
<script src="https://sg-webapi.opnavi.com/maps?v=2.0&key=b87b3d194a024295b1b17be020659457&appname=amap-map-google-maps-migration"></script>
</head>
<body>
<div id="map" style="width:100%;height:400px;"></div>
<script>
const map = new AMap.Map('map', {
center: [103.8198, 1.3521], zoom: 13 // [lng, lat]
});
const marker = new AMap.Marker({
position: [103.8198, 1.3521], map: map, title: 'Singapore'
});
const iw = new AMap.InfoWindow({
content: '<h3>Singapore</h3>', offset: new AMap.Pixel(0, -30)
});
marker.on('click', () => iw.open(map, marker.getPosition()));
map.on('click', (e) => {
console.log(e.lnglat.getLat(), e.lnglat.getLng());
});
</script>
</body>
</html>
```
### Key Changes Summary
1. Script tag → dual auth + AMap CDN
2. `document.getElementById('map')` → `'map'` (string ID)
3. `{lat, lng}` → `[lng, lat]`
4. `google.maps.Map` → `AMap.Map`
5. `google.maps.Marker` → `AMap.Marker`
6. `google.maps.InfoWindow` → `AMap.InfoWindow` + `offset` + `.open(map, position)`
7. `marker.addListener(...)` → `marker.on(...)`
8. `e.latLng.lat()` → `e.lnglat.getLat()`
高德地图个人专属地图生成工具。封装了高德开放平台的Web服务API,提供地理编码、POI搜索、路径规划、周边搜索、天气查询等能力,最终生成可在高德地图App中打开的个人地图小程序二维码。当用户提到以下任意场景时,都应主动使用本技能:查找附近的餐厅/景点/商场等POI、规划从A到B的路线(步行/驾车/公交/骑行)、...
---
name: personal-map
display_name: Gaode Map Personal - 高德官方个人专属地图 Skill
description: 高德地图个人专属地图生成工具。封装了高德开放平台的Web服务API,提供地理编码、POI搜索、路径规划、周边搜索、天气查询等能力,最终生成可在高德地图App中打开的个人地图小程序二维码。当用户提到以下任意场景时,都应主动使用本技能:查找附近的餐厅/景点/商场等POI、规划从A到B的路线(步行/驾车/公交/骑行)、生成旅游行程/出行计划/打卡地图、在地图上标记多个地点、分享地图给他人、查询某地天气、将地址转换为坐标或反向解析、制作个人专属地图、行程规划、路线规划、地图分享。即使用户没有明确说"生成地图",只要涉及地理位置、出行、导航、打卡、行程等话题,都应考虑使用本技能。
version: 1.0.0
author: 高德开放平台
tags:
- 地图
- 高德
- Map
- 个人地图
- POI
- 路径规划
metadata:
openclaw:
requires:
env:
- AMAP_API_KEY
primaryEnv: AMAP_API_KEY
---
# 高德个人地图 Skill
## 概述
本 Skill 封装了高德开放平台的 Web 服务 API,提供地理编码、POI 搜索、路径规划等核心能力,根据用户描述生成个人专属地图,并支持在高德地图 App 中扫码打开。
**重要**:所有调用此技能的会话,最终都应调用 `maps_schema_personal_map` 生成个人地图二维码,并通过以下方式展示给用户:
1. **下载二维码图片到本地**(推荐保存到工作目录)
2. **使用 `present` 工具展示图片**
3. **在回复中直接嵌入 Markdown 图片**(双重保障)
4. **提供备用 URL 链接**(防止图片展示失败)
这样可以确保用户能够可靠地看到并保存二维码。
## 接口说明
### 1. 地理编码
- **`maps_geo`**:地址 → 经纬度坐标
- 参数:`address`(详细地址)、`city`(城市,可选)
- 返回:经纬度坐标、格式化地址
- **`maps_regeocode`**:经纬度坐标 → 结构化地址
- 参数:`longitude`(经度)、`latitude`(纬度)
- 返回:国家、省份、城市、区县等完整地址信息
### 2. POI 搜索
- **`maps_text_search`**:关键词搜索兴趣点
- 参数:`keywords`(搜索关键词)、`city`(城市,可选)、`offset`(每页记录数,默认 20)
- 返回:POI 列表(名称、坐标、地址、电话)
- **`maps_around_search`**:周边兴趣点搜索
- 参数:`keywords`、`location`(中心点"经度,纬度")、`radius`(搜索半径,单位米,默认 1000)、`types`(POI 类型,可选)、`offset`(默认 20)、`page`(默认 1)
- 返回:周边 POI 列表(含距离信息)
### 3. 路径规划
- **`maps_direction_walking`**:步行路线规划
- 参数:`origin`(起点"经度,纬度")、`destination`(终点"经度,纬度")
- **`maps_direction_driving`**:驾车路线规划
- 参数:`origin`、`destination`
- **`maps_direction_transit_integrated`**:公共交通路线规划
- 参数:`origin`、`destination`、`city`(城市,默认"北京")
### 4. 位置服务
- **`maps_ip_location`**:IP 地址 → 地理位置
- 参数:`ip`(IP 地址)
- 返回:省份、城市、行政区、ISP 等信息
### 5. 地图生成(核心)
- **`maps_schema_personal_map`**:生成个人地图小程序二维码
- 参数:
- `orgName`(地图名称)
- `lineList`(行程列表,每条路线最多 16 个点)
- `sceneType`(场景类型,可选,默认 `1`):
- `1` — 创建资源点且创建路线(默认,通用场景)
- `2` — 仅创建资源点(搜索类数据,多个点之间无关联关系)
- `3` — 仅创建路线(路径规划类数据,多个点有关联关系,如起终点、换乘点)
- 返回:`qr_code_url`(二维码图片链接)、`lineList`(行程数据)
**sceneType 选择指引:**
- 用户做的是**搜索**(找餐厅、找景点、找周边 POI 等)→ 用 `sceneType=2`
- 用户做的是**路径规划**(从 A 到 B、导航、换乘等)→ 用 `sceneType=3`
- 两者都有,或不确定 → 用默认 `sceneType=1`
## 使用前提
1. 申请高德地图开发者账号并获取 API Key(https://lbs.amap.com/)
2. 配置环境变量:`export AMAP_API_KEY='your_api_key_here'`
3. 确保网络连接正常
## 异常处理
所有接口在出错时均返回结构化错误信息,不会抛出异常:
```python
{"error": "错误类型", "message": "具体原因"}
```
常见错误类型:`API Key 缺失`、`请求失败`、`搜索失败`、`路径规划失败`、`生成地图行程失败`。
检查返回值的推荐方式:
```python
result = client.maps_text_search("餐厅", "北京")
if isinstance(result, list) and result and "error" in result[0]:
print(f"错误: {result[0]['message']}")
```
## 使用示例
### 初始化客户端
```python
from scripts.amap_personal_map_client import AMapPersonalMapClient
client = AMapPersonalMapClient() # 读取环境变量 AMAP_API_KEY
# 或直接传入:client = AMapPersonalMapClient(api_key='your_api_key_here')
```
### 地理编码
```python
# 地址转坐标
result = client.maps_geo("北京市朝阳区三里屯", "北京")
print(f"经度: {result['longitude']}, 纬度: {result['latitude']}")
# 坐标转地址
result = client.maps_regeocode(116.447716, 39.906736)
print(f"完整地址: {result['formatted_address']}")
```
### POI 搜索
```python
# 关键词搜索
pois = client.maps_text_search("烤鸭", "北京", offset=20)
for poi in pois:
print(f"{poi['name']} - {poi['address']}")
# 周边搜索
pois = client.maps_around_search(keywords="餐厅", location="116.397451,39.909221", radius=1000)
for poi in pois:
print(f"{poi['name']}, 距离: {poi.get('distance', '未知')}米")
```
### 路径规划
```python
# 步行
result = client.maps_direction_walking("116.397451,39.909221", "116.397029,39.917839")
# 驾车
result = client.maps_direction_driving("116.397451,39.909221", "116.397029,39.917839")
# 公共交通
result = client.maps_direction_transit_integrated("116.397451,39.909221", "116.397029,39.917839", city="北京")
```
### 生成个人地图(最终步骤)
```python
import urllib.request
from scripts.amap_personal_map_client import AMapPersonalMapClient
client = AMapPersonalMapClient()
line_list = [{
"title": "北京市中心一日游",
"pointInfoList": [
{"name": "天安门广场", "lon": 116.397451, "lat": 39.909221, "poiId": "B000A8URXB"},
{"name": "故宫博物院", "lon": 116.397029, "lat": 39.917839, "poiId": "B000A8URXC"}
]
}]
# 搜索类数据 → sceneType=2(仅创建资源点)
result = client.maps_schema_personal_map("北京热门景点", line_list, sceneType=2)
# 路径规划类数据 → sceneType=3(仅创建路线)
result = client.maps_schema_personal_map("北京一日游路线", line_list, sceneType=3)
# 通用场景(默认)
result = client.maps_schema_personal_map("北京市中心一日游", line_list)
# 下载并保存二维码图片到本地
qr_url = result['qr_code_url']
output_path = '/path/to/output/个人地图二维码.png'
urllib.request.urlretrieve(qr_url, output_path)
# 使用 present 工具展示图片(实际使用时通过工具调用)
# present(artifacts=[output_path])
# 在回复中嵌入 Markdown 图片(双重保障)
print(f"")
# 提供备用 URL 链接
print(f"备用链接: {qr_url}")
```
### 会话管理
AMAP_API_KEY 配置正常的前提下,每次会话结束请调用 `maps_schema_personal_map` 生成个人地图二维码,并**按以下步骤展示**:
1. **下载二维码图片**:使用 `urllib.request.urlretrieve()` 将二维码保存到本地工作目录
2. **调用 `present` 工具**:将保存的图片路径传入 `present` 工具展示
3. **Markdown 嵌入**:在回复中使用 `` 格式嵌入图片
4. **提供备用链接**:同时输出二维码的原始 URL,以防图片展示失败
用户可以通过高德地图 App 扫描二维码打开个人地图小程序页。
**最佳实践示例:**
```python
import urllib.request
from scripts.amap_personal_map_client import AMapPersonalMapClient
client = AMapPersonalMapClient()
# ... 搜索/规划逻辑 ...
result = client.maps_schema_personal_map("我的地图", line_list, sceneType=2)
# 1. 保存二维码到本地
qr_path = '/workspace/我的地图二维码.png'
urllib.request.urlretrieve(result['qr_code_url'], qr_path)
# 2. 调用 present 工具展示
# present(artifacts=[qr_path])
# 3. 在回复中嵌入图片和备用链接
print(f"")
print(f"备用链接: {result['qr_code_url']}")
```
## logo

## 使用场景
1. 旅游路线规划与地图分享
2. 周边 POI 搜索与标记
3. 通勤/出行路径规划
4. 商业选址与市场分析
5. 物流配送路径优化
## changelog
### v1.2.0
- `maps_schema_personal_map` 新增 `sceneType` 参数,支持按场景控制创建资源点/路线
### v1.1.0
- 新增骑行路线规划功能
- 新增 URI 生成功能(导航页面唤起、打车页面唤起)
- 完善会话管理机制,提升用户体验
- 优化错误处理和异常情况应对
### v1.0.0
- 初始版本发布
- 支持地理编码、POI 搜索、路径规划等核心功能
- 支持生成个人地图小程序二维码
- 支持会话管理与二维码自动生成
FILE:config.json
{
"skill": {
"name": "personal-map",
"version": "1.0.0",
"description": "高德个人地图Skill,直接调用高德地图官方RESTful API,提供完整的地理信息服务能力,并支持地图在高德App中扫码查看及分析给他人",
"author": "高德开放平台",
"license": "MIT"
},
"dependencies": {
"requests": "^2.25.1"
},
"env_vars": {
"AMAP_API_KEY": {
"description": "高德地图API Key。首次使用时,系统会自动检测并提示配置。获取步骤:1. 访问 https://lbs.amap.com/ 2. 注册/登录账号 3. 创建应用获取 Web服务 API Key。配置方式:export AMAP_API_KEY='your_api_key_here' 或在初始化时传入",
"required": true
}
},
"entry_point": "scripts/amap_personal_map_client.py"
}
FILE:examples/demo_usage.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
高德地图REST API Skill使用示例
演示如何使用AMapPersonalMapClient实现各种地理信息服务
"""
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'scripts'))
from amap_personal_map_client import AMapPersonalMapClient
import json
def demo_basic_services():
"""演示基本服务功能"""
print("=== 基本服务功能演示 ===")
# 初始化客户端
client = AMapPersonalMapClient(os.getenv("AMAP_API_KEY"))
# 1. 地理编码服务
print("1. 地理编码服务:")
result = client.maps_geo("天安门广场", "北京")
print(json.dumps(result, ensure_ascii=False, indent=2))
# 2. 逆地理编码服务
print("\n2. 逆地理编码服务:")
result = client.maps_regeocode(116.397451, 39.909221)
print(json.dumps(result, ensure_ascii=False, indent=2))
def demo_poi_services():
"""演示POI服务功能"""
print("\n=== POI服务功能演示 ===")
# 初始化客户端
client = AMapPersonalMapClient(os.getenv("AMAP_API_KEY"))
# 3. 关键词搜索POI
print("3. 关键词搜索POI:")
pois = client.maps_text_search("烤鸭", "北京", offset=3)
print(json.dumps(pois, ensure_ascii=False, indent=2))
# 4. 周边搜索POI
print("\n4. 周边搜索POI:")
pois = client.maps_around_search("餐厅", "116.397451,39.909221", radius=1000, offset=3)
print(json.dumps(pois, ensure_ascii=False, indent=2))
def demo_routing_services():
"""演示路径规划服务功能"""
print("\n=== 路径规划服务功能演示 ===")
# 初始化客户端
client = AMapPersonalMapClient(os.getenv("AMAP_API_KEY"))
# 5. 步行路线规划
print("5. 步行路线规划:")
route = client.maps_direction_walking("116.397451,39.909221", "116.397029,39.917839")
if "error" not in route:
distance = route.get("route", {}).get("paths", [{}])[0].get("distance", "未知")
duration = route.get("route", {}).get("paths", [{}])[0].get("duration", "未知")
print("步行距离: {}米, 预计时间: {}秒".format(distance, duration))
else:
print(json.dumps(route, ensure_ascii=False, indent=2))
# 6. 驾车路线规划
print("\n6. 驾车路线规划:")
route = client.maps_direction_driving("116.397451,39.909221", "116.397029,39.917839")
if "error" not in route:
distance = route.get("route", {}).get("paths", [{}])[0].get("distance", "未知")
duration = route.get("route", {}).get("paths", [{}])[0].get("duration", "未知")
print("驾车距离: {}米, 预计时间: {}秒".format(distance, duration))
else:
print(json.dumps(route, ensure_ascii=False, indent=2))
# 7. 公共交通路线规划
print("\n7. 公共交通路线规划:")
route = client.maps_direction_transit_integrated("116.397451,39.909221", "116.397029,39.917839", "北京")
if "error" not in route:
distance = route.get("route", {}).get("transits", [{}])[0].get("distance", "未知")
duration = route.get("route", {}).get("transits", [{}])[0].get("duration", "未知")
print("公交距离: {}米, 预计时间: {}秒".format(distance, duration))
else:
print(json.dumps(route, ensure_ascii=False, indent=2))
def demo_other_services():
"""演示其他服务功能"""
print("\n=== 其他服务功能演示 ===")
# 初始化客户端
client = AMapPersonalMapClient(os.getenv("AMAP_API_KEY"))
# 9. IP定位服务
print("9. IP定位服务:")
result = client.maps_ip_location("114.114.114.114")
print(json.dumps(result, ensure_ascii=False, indent=2))
def demo_map_services():
"""演示地图展示服务功能 - 包含二维码下载和展示最佳实践"""
print("\n=== 地图展示服务功能演示 ===")
# 初始化客户端
client = AMapPersonalMapClient(os.getenv("AMAP_API_KEY"))
# 12. 生成个人地图行程(WIA小程序版本)
print("12. 生成个人地图行程(WIA小程序版本):")
line_list = [
{
"title": "北京市中心一日游",
"pointInfoList": [
{
"name": "天安门广场",
"lon": 116.397451,
"lat": 39.909221,
"poiId": "B000A8URXB"
},
{
"name": "故宫博物院",
"lon": 116.397029,
"lat": 39.917839,
"poiId": "B000A8URXC"
}
]
}
]
# sceneType 说明:
# 1 - 创建资源点 且 创建路线(默认,通用场景)
# 2 - 仅创建资源点(搜索类数据,多个点无关联关系)
# 3 - 仅创建路线(路径规划类数据,多个点有关联关系,如起终点/换乘点)
map_info = client.maps_schema_personal_map("北京经典景点游", line_list, sceneType=2)
if "error" not in map_info:
print("高德地图WIA小程序链接:", map_info.get("schema_url", ""))
print("二维码图片链接:", map_info.get("qr_code_url", ""))
# ========== 二维码展示最佳实践 ==========
# 1. 下载二维码到本地
import urllib.request
import os
# 设置输出路径(根据实际环境调整)
output_dir = os.path.expanduser("~/.qoderwork/workspace")
os.makedirs(output_dir, exist_ok=True)
qr_path = os.path.join(output_dir, "北京经典景点游_二维码.png")
try:
urllib.request.urlretrieve(map_info["qr_code_url"], qr_path)
print(f"\n✅ 二维码已保存到: {qr_path}")
# 2. 在回复中嵌入 Markdown 图片(双重保障)
print(f"\n")
# 3. 提供备用链接
print(f"\n备用链接(如果图片无法显示): {map_info['qr_code_url']}")
# 4. 使用 present 工具展示(实际使用时调用)
# from qoderwork.tools import present
# present(artifacts=[qr_path])
except Exception as e:
print(f"\n⚠️ 下载二维码失败: {e}")
print(f"请直接访问二维码链接: {map_info['qr_code_url']}")
else:
print("生成失败:", map_info["message"])
def main():
"""主函数"""
try:
demo_basic_services()
demo_poi_services()
demo_routing_services()
demo_other_services()
demo_map_services()
print("\n🎉 所有功能演示完成!")
except Exception as e:
print("❌ 演示过程中出现错误: {}".format(str(e)))
import traceback
traceback.print_exc()
if __name__ == "__main__":
main()
FILE:requirements.txt
# 高德地图 Personal-Map Skill 依赖包
#
# 安装方式:
# pip install -r requirements.txt
#
# 或者使用虚拟环境:
# python -m venv venv
# source venv/bin/activate # Linux/Mac
# # 或 venv\Scripts\activate # Windows
# pip install -r requirements.txt
# HTTP 请求库,用于调用高德地图 API
requests>=2.25.1
FILE:scripts/amap_personal_map_client.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
高德地图WIA客户端
提供完整的地理信息服务能力,支持生成个人地图小程序二维码,并支持会话管理和自动生成二维码功能
"""
import os
import json
import uuid
import requests
import urllib.parse as urlparse
from datetime import datetime
def _generate_qr_code_url(schema_url, size="300x300"):
"""
生成二维码图片URL
Args:
schema_url (str): 高德地图schema链接
size (str): 二维码尺寸,默认300x300
Returns:
str: 二维码图片URL
"""
# 使用在线二维码生成服务
qr_service = "https://api.qrserver.com/v1/create-qr-code/"
encoded_url = urlparse.quote(schema_url)
qr_url = "{}?size={}&data={}".format(qr_service, size, encoded_url)
return qr_url
def download_qr_code(qr_code_url, output_path):
"""
下载二维码图片到本地
Args:
qr_code_url (str): 二维码图片URL
output_path (str): 本地保存路径
Returns:
str: 本地文件路径,下载失败则返回 None
"""
try:
import urllib.request
urllib.request.urlretrieve(qr_code_url, output_path)
return output_path
except Exception as e:
print(f"下载二维码失败: {e}")
return None
class AMapPersonalMapClient:
def __init__(self, api_key=None):
"""
初始化高德地图WIA客户端
Args:
api_key (str): 高德地图API Key
"""
self.api_key = api_key or os.getenv('AMAP_API_KEY')
if not self.api_key:
# 不再抛出异常,而是设置一个标志,让后续方法能够检测到 API Key 缺失
self.api_key_missing = True
else:
self.api_key_missing = False
self.base_url = "https://restapi.amap.com/v3"
self.wia_base_url = "https://restapi.amap.com"
# 初始化会话管理
self.session_id = str(uuid.uuid4())
self.session_start_time = datetime.now()
self.session_data = {
"points_of_interest": [],
"routes": [],
"personal_maps": []
}
def _track_poi(self, poi_info):
"""跟踪POI信息"""
if poi_info and isinstance(poi_info, dict) and "error" not in poi_info:
self.session_data["points_of_interest"].append({
"timestamp": datetime.now().isoformat(),
"poi_info": poi_info
})
def _track_route(self, route_info, route_type):
"""跟踪路线信息"""
if route_info and isinstance(route_info, dict) and "error" not in route_info:
self.session_data["routes"].append({
"timestamp": datetime.now().isoformat(),
"route_type": route_type,
"route_info": route_info
})
def _track_personal_map(self, map_info):
"""跟踪个人地图信息"""
if map_info and isinstance(map_info, dict) and "error" not in map_info:
self.session_data["personal_maps"].append({
"timestamp": datetime.now().isoformat(),
"map_info": map_info
})
def _get_api_key_missing_error(self):
"""获取 API Key 缺失的错误信息"""
return {
"error": "API Key 缺失",
"message": "⚠️ 未检测到高德地图 API Key\n\n"
"📝 请按照以下步骤配置 API Key:\n"
" 1. 访问高德开放平台:https://lbs.amap.com/\n"
" 2. 注册/登录账号,进入控制台\n"
" 3. 创建应用,获取 Web服务 API Key\n"
" 4. 设置环境变量:export AMAP_API_KEY='your_api_key_here'\n"
" 5. 或者在初始化时传入:client = AMapPersonalMapClient('your_api_key_here')\n\n"
"💡 提示:API Key 是使用高德地图服务的必要凭证,请确保已正确配置"
}
def maps_text_search(self, keywords, city=None, offset=20):
"""
搜索兴趣点(带会话跟踪)
Args:
keywords (str): 搜索关键词
city (str, optional): 城市名称
offset (int): 每页记录数
Returns:
list: POI信息列表
"""
# 检查 API Key 是否缺失
if self.api_key_missing:
return [self._get_api_key_missing_error()]
params = {
"key": self.api_key,
"keywords": keywords,
"offset": min(offset, 100),
"page": 1
}
if city:
params["city"] = city
try:
response = requests.get("{}/place/text".format(self.base_url), params=params, timeout=10)
result = response.json()
if result["status"] == "1":
pois = []
for poi in result.get("pois", []):
location = poi.get("location", "")
if location:
lon, lat = location.split(",")
else:
lon, lat = "", ""
pois.append({
"id": poi.get("id", ""),
"name": poi.get("name", ""),
"location": {
"longitude": float(lon) if lon else None,
"latitude": float(lat) if lat else None
},
"address": poi.get("address", ""),
"tel": poi.get("tel", "")
})
# 跟踪POI搜索结果
self._track_poi({"keywords": keywords, "city": city, "results": pois})
return pois
else:
error_result = [{"error": "搜索失败", "message": result.get("info", "未知错误")}]
self._track_poi({"keywords": keywords, "city": city, "results": error_result})
return error_result
except Exception as e:
error_result = [{"error": "请求失败", "message": str(e)}]
self._track_poi({"keywords": keywords, "city": city, "results": error_result})
return error_result
def maps_around_search(self, keywords, location, radius=1000, types=None, offset=20, page=1):
"""
周边搜索兴趣点(带会话跟踪)
Args:
keywords (str): 搜索关键词
location (str): 中心点坐标,格式为"经度,纬度"
radius (int): 搜索半径,单位米,默认1000米
types (str, optional): POI类型
offset (int): 每页记录数
page (int): 页码
Returns:
list: POI信息列表
"""
# 检查 API Key 是否缺失
if self.api_key_missing:
return [self._get_api_key_missing_error()]
params = {
"key": self.api_key,
"keywords": keywords,
"location": location,
"radius": radius,
"offset": min(offset, 100),
"page": page
}
if types:
params["types"] = types
try:
response = requests.get("{}/place/around".format(self.base_url), params=params, timeout=10)
result = response.json()
if result["status"] == "1":
pois = []
for poi in result.get("pois", []):
location = poi.get("location", "")
if location:
lon, lat = location.split(",")
else:
lon, lat = "", ""
pois.append({
"id": poi.get("id", ""),
"name": poi.get("name", ""),
"location": {
"longitude": float(lon) if lon else None,
"latitude": float(lat) if lat else None
},
"address": poi.get("address", ""),
"tel": poi.get("tel", ""),
"distance": poi.get("distance", "") # 距离中心点的距离
})
# 跟踪周边搜索结果
self._track_poi({"keywords": keywords, "location": location, "radius": radius, "results": pois})
return pois
else:
error_result = [{"error": "周边搜索失败", "message": result.get("info", "未知错误")}]
self._track_poi({"keywords": keywords, "location": location, "radius": radius, "results": error_result})
return error_result
except Exception as e:
error_result = [{"error": "请求失败", "message": str(e)}]
self._track_poi({"keywords": keywords, "location": location, "radius": radius, "results": error_result})
return error_result
def maps_ip_location(self, ip):
"""
根据IP地址获取地理位置信息
Args:
ip (str): IP地址
Returns:
dict: 包含地理位置信息的字典
"""
# 检查 API Key 是否缺失
if self.api_key_missing:
return self._get_api_key_missing_error()
params = {
"key": self.api_key,
"ip": ip
}
try:
response = requests.get("{}/ip".format(self.base_url), params=params, timeout=10)
result = response.json()
if result["status"] == "1":
location_result = {
"province": result.get("province", ""),
"city": result.get("city", ""),
"adcode": result.get("adcode", ""),
"rectangle": result.get("rectangle", ""),
"isp": result.get("isp", ""),
"location": result.get("loc", ""),
"ip": ip
}
# 跟踪IP定位结果
self._track_poi({"ip": ip, "result": location_result})
return location_result
else:
error_result = {
"error": "IP定位失败",
"message": result.get("info", "未知错误")
}
self._track_poi({"ip": ip, "result": error_result})
return error_result
except Exception as e:
error_result = {
"error": "请求失败",
"message": str(e)
}
self._track_poi({"ip": ip, "result": error_result})
return error_result
def maps_geo(self, address, city=None):
"""
将详细地址转换为经纬度坐标
Args:
address (str): 详细地址
city (str, optional): 城市名称
Returns:
dict: 包含经纬度信息的字典
"""
# 检查 API Key 是否缺失
if self.api_key_missing:
return self._get_api_key_missing_error()
params = {
"key": self.api_key,
"address": address
}
if city:
params["city"] = city
try:
response = requests.get("{}/geocode/geo".format(self.base_url), params=params, timeout=10)
result = response.json()
if result["status"] == "1" and int(result["count"]) > 0:
location = result["geocodes"][0]["location"]
lon, lat = location.split(",")
geocode_result = {
"longitude": float(lon),
"latitude": float(lat),
"formatted_address": result["geocodes"][0].get("formatted_address", "")
}
# 跟踪地理编码结果
self._track_poi({"address": address, "city": city, "result": geocode_result})
return geocode_result
else:
error_result = {
"error": "无法找到该地址",
"message": result.get("info", "未知错误")
}
self._track_poi({"address": address, "city": city, "result": error_result})
return error_result
except Exception as e:
error_result = {
"error": "请求失败",
"message": str(e)
}
self._track_poi({"address": address, "city": city, "result": error_result})
return error_result
def maps_regeocode(self, longitude, latitude):
"""
将经纬度坐标转换为结构化地址信息
Args:
longitude (float): 经度
latitude (float): 纬度
Returns:
dict: 包含地址信息的字典
"""
# 检查 API Key 是否缺失
if self.api_key_missing:
return self._get_api_key_missing_error()
params = {
"key": self.api_key,
"location": "{},{}".format(longitude, latitude),
"poitype": "",
"radius": 1000,
"extensions": "base",
"batch": "false",
"roadlevel": 0
}
try:
response = requests.get("{}/geocode/regeo".format(self.base_url), params=params, timeout=10)
result = response.json()
if result["status"] == "1":
regeocode = result["regeocode"]
regeocode_result = {
"formatted_address": regeocode.get("formatted_address", ""),
"country": regeocode["addressComponent"].get("country", ""),
"province": regeocode["addressComponent"].get("province", ""),
"city": regeocode["addressComponent"].get("city", ""),
"district": regeocode["addressComponent"].get("district", "")
}
# 跟踪逆地理编码结果
self._track_poi({"location": {"longitude": longitude, "latitude": latitude}, "result": regeocode_result})
return regeocode_result
else:
error_result = {
"error": "逆地理编码失败",
"message": result.get("info", "未知错误")
}
self._track_poi({"location": {"longitude": longitude, "latitude": latitude}, "result": error_result})
return error_result
except Exception as e:
error_result = {
"error": "请求失败",
"message": str(e)
}
self._track_poi({"location": {"longitude": longitude, "latitude": latitude}, "result": error_result})
return error_result
def maps_direction_walking(self, origin, destination):
"""
步行路线规划
Args:
origin (str): 起点坐标,格式为"经度,纬度"
destination (str): 终点坐标,格式为"经度,纬度"
Returns:
dict: 路线规划信息
"""
# 检查 API Key 是否缺失
if self.api_key_missing:
return self._get_api_key_missing_error()
params = {
"key": self.api_key,
"origin": origin,
"destination": destination
}
try:
response = requests.get("{}/direction/walking".format(self.base_url), params=params, timeout=15)
result = response.json()
if result["status"] == "1":
# 跟踪步行路线规划结果
self._track_route(result, "walking")
return result
else:
error_result = {
"error": "路径规划失败",
"message": result.get("info", "未知错误")
}
self._track_route(error_result, "walking")
return error_result
except Exception as e:
error_result = {
"error": "请求失败",
"message": str(e)
}
self._track_route(error_result, "walking")
return error_result
def maps_direction_driving(self, origin, destination):
"""
驾车路线规划
Args:
origin (str): 起点坐标,格式为"经度,纬度"
destination (str): 终点坐标,格式为"经度,纬度"
Returns:
dict: 路线规划信息
"""
# 检查 API Key 是否缺失
if self.api_key_missing:
return self._get_api_key_missing_error()
params = {
"key": self.api_key,
"origin": origin,
"destination": destination
}
try:
response = requests.get("{}/direction/driving".format(self.base_url), params=params, timeout=15)
result = response.json()
if result["status"] == "1":
# 跟踪驾车路线规划结果
self._track_route(result, "driving")
return result
else:
error_result = {
"error": "路径规划失败",
"message": result.get("info", "未知错误")
}
self._track_route(error_result, "driving")
return error_result
except Exception as e:
error_result = {
"error": "请求失败",
"message": str(e)
}
self._track_route(error_result, "driving")
return error_result
def maps_direction_transit_integrated(self, origin, destination, city="北京"):
"""
公共交通路线规划
Args:
origin (str): 起点坐标,格式为"经度,纬度"
destination (str): 终点坐标,格式为"经度,纬度"
city (str): 城市名称
Returns:
dict: 路线规划信息
"""
# 检查 API Key 是否缺失
if self.api_key_missing:
return self._get_api_key_missing_error()
params = {
"key": self.api_key,
"origin": origin,
"destination": destination,
"city": city
}
try:
response = requests.get("{}/direction/transit/integrated".format(self.base_url), params=params, timeout=15)
result = response.json()
if result["status"] == "1":
# 跟踪公共交通路线规划结果
self._track_route(result, "transit")
return result
else:
error_result = {
"error": "路径规划失败",
"message": result.get("info", "未知错误")
}
self._track_route(error_result, "transit")
return error_result
except Exception as e:
error_result = {
"error": "请求失败",
"message": str(e)
}
self._track_route(error_result, "transit")
return error_result
def maps_schema_personal_map(self, orgName, lineList, sceneType=1):
"""
生成个人地图小程序二维码
Args:
orgName (str): 行程规划地图小程序名称
lineList (list): 行程列表
sceneType (int): 场景类型,控制创建内容:
1 - 创建资源点 且 创建路线(默认)
2 - 仅创建资源点(适用于搜索类数据,多个数据点无关联关系)
3 - 仅创建路线(适用于路径规划类数据,多个点有关联关系,如起终点或换乘点)
Returns:
dict: 包含小程序二维码图片链接的信息
"""
# 检查 API Key 是否缺失
if self.api_key_missing:
return self._get_api_key_missing_error()
# sceneType 合法值校验,缺省时默认为 1
valid_scene_types = {1, 2, 3}
if sceneType not in valid_scene_types:
sceneType = 1
try:
# 构造请求参数
payload = {
"channel": "60000001",
"orgName": orgName,
"lineList": lineList,
"sceneType": sceneType
}
# 发送POST请求到WIA服务
wia_url = "{}/rest/wia/mcp/schema".format(self.wia_base_url)
params = {
"key": self.api_key,
"source": "personal-map"
}
headers = {
"Content-Type": "application/json"
}
response = requests.post(wia_url, params=params, json=payload, headers=headers, timeout=15)
result = response.json()
# 检查响应状态
# API返回的结构是: {"code": 1, "message": "Successful", "result": true, "data": {...}}
if result.get("code") == 1 and result.get("result") == True:
schema_url = result.get("data", {}).get("schemaUrl", "")
if schema_url:
# 生成二维码图片链接
qr_code_url = _generate_qr_code_url(schema_url)
map_result = {
"qr_code_url": qr_code_url, # 小程序二维码图片链接
"lineList": lineList, # 数据信息
"message": "📱 个人地图小程序二维码已生成!请使用高德地图App扫描下方二维码查看您的专属地图。", # 提示信息
"schema_url": schema_url # 原始schema链接
}
# 跟踪个人地图生成结果
self._track_personal_map(map_result)
return map_result
else:
error_result = {
"error": "生成地图行程失败",
"message": "未返回有效的行程链接"
}
self._track_personal_map(error_result)
return error_result
else:
# 处理错误信息
error_info = result.get("message") or result.get("info") or "未知错误"
error_result = {
"error": "生成地图行程失败",
"message": error_info
}
self._track_personal_map(error_result)
return error_result
except Exception as e:
error_result = {
"error": "请求失败",
"message": str(e)
}
self._track_personal_map(error_result)
return error_result
def main():
"""主函数示例"""
try:
# 初始化高德地图WIA客户端
api_key = os.getenv("AMAP_API_KEY")
client = AMapPersonalMapClient(api_key)
# 示例:搜索天安门广场
print("搜索天安门广场...")
attractions = client.maps_text_search("天安门广场", "北京", offset=1)
if attractions and isinstance(attractions, list) and len(attractions) > 0 and "error" not in attractions[0]:
print(f"✓ 找到天安门广场: {attractions[0]['name']}")
# 示例:地理编码
print("地理编码...")
geo_result = client.maps_geo("北京市朝阳区三里屯", "北京")
if "error" not in geo_result:
print(f"✓ 找到三里屯坐标: ({geo_result['longitude']}, {geo_result['latitude']})")
# 示例:生成个人地图行程
line_list = [{
"title": "北京探索之旅",
"pointInfoList": [
{
"name": "天安门广场",
"lon": 116.397451,
"lat": 39.909221,
"poiId": "B000A83M6N"
}
]
}]
print("生成个人地图行程...")
result = client.maps_schema_personal_map("北京探索之旅", line_list)
if "error" not in result:
print("\n✅ 高德地图个人专属地图页面创建完成!")
print(f"📱 高德地图行程链接: {result['schemaUrl']}")
print("\n在高德地图App中打开上述链接即可查看个人专属地图页面!")
else:
print(f"\n❌ 生成地图链接失败: {result['message']}")
if "error" not in qr_result:
print("\n✅ 会话结束!")
print(f"📱 高德地图链接: {qr_result.get('schemaUrl')}")
print(f"💬 {qr_result.get('message')}")
print("\n在高德地图App中打开上述链接即可查看地图页面!")
else:
print(f"\n❌ 生成地图链接失败: {qr_result['message']}")
except Exception as e:
print(f"\n❌ 程序执行出错: {str(e)}")
if __name__ == "__main__":
main()Map Agent - 高德地图 AI 智能助手 Android SDK 开发指南,支持自然语言交互的 Map 导航服务,涵盖快速接入、AI 查询、结果处理、高德 Map APP 联动等完整能力
---
name: android-llm-agent-sdk
display_name: Map Agent - Android LLM Agent SDK(高德官方 AI Agent Skill)
version: 1.0.2
description: Map Agent - 高德地图 AI 智能助手 Android SDK 开发指南,支持自然语言交互的 Map 导航服务,涵盖快速接入、AI 查询、结果处理、高德 Map APP 联动等完整能力
author: 高德开放平台
tags:
- 地图
- 高德
- Map
- Android
- LLM
- Agent
- SDK
- AMap
---
# Map Agent - Android LLM Agent SDK(高德官方 AI Agent Skill)
AMap LLM Agent SDK 是高德地图 AI 智能助手 SDK,支持自然语言交互的地图导航服务。
## 触发词
- "接入LLM Agent SDK"、"集成AI助手"、"接入Agent"
- "连接高德APP"、"配置LinkClient"
## 目录结构
```
amap-llm-agent/
├── SKILL.md # 本文件 - 入口索引
├── api/ # API 使用指南
│ ├── quick-start.md # 快速接入(3步完成)
│ ├── agent-query.md # 发送 AI 查询
│ ├── query-result.md # 处理查询结果
│ ├── link-client.md # LinkClient 与高德APP通信
│ ├── transport-mode.md # 切换导航模式
│ ├── logger.md # 日志配置
│ └── lifecycle.md # 生命周期管理
└── references/ # 参考资料
├── voice-commands.md # 支持的语音指令
├── troubleshooting.md # 常见问题诊断
└── core-classes.md # 核心类说明
```
## 快速导航
| 需求 | 参考文档 |
|-----|---------|
| 首次接入 SDK | [api/quick-start.md](api/quick-start.md) |
| 发送语音/文字查询 | [api/agent-query.md](api/agent-query.md) |
| 处理 AI 返回结果 | [api/query-result.md](api/query-result.md) |
| 与高德 APP 联动 | [api/link-client.md](api/link-client.md) |
| 切换驾车/骑行/步行 | [api/transport-mode.md](api/transport-mode.md) |
| 查看支持的语音指令 | [references/voice-commands.md](references/voice-commands.md) |
| 排查问题 | [references/troubleshooting.md](references/troubleshooting.md) |
## 依赖版本
```gradle
// LLM Agent SDK
implementation 'com.amap.lbs.client:amap-agent:1.1.41'
// 导航 SDK(必须)
implementation 'com.amap.api:navi-3dmap:latest.integration'
// 定位 SDK(必须,用于实时位置更新)
implementation 'com.amap.api:location:latest.integration'
```
> ⚠️ **注意**:如果 Agent SDK 或导航 SDK 依赖有问题(如无法下载、版本冲突等),请联系高德相关同学获取依赖包。
FILE:README.md
# Android LLM Agent SDK Skills User Guide
[🇨🇳 中文文档](./README_zh.md) | [⬆️ Back to Home](../README.md)
## Product Introduction
**AMap Android LLM Agent SDK Skills** is an AI programming skill package designed for AI IDEs. It integrates the official documentation, best practices, and code templates of the AMap LLM Agent SDK for Android into structured skill files, enabling AI coding tools like Cursor, Claude, and Cline to:
- **Accurately understand** how to integrate the AI-powered navigation assistant into Android apps
- **Automatically generate** SDK initialization, query, and navigation control code
- **Proactively avoid** common integration issues such as dependency conflicts and lifecycle management
- **Provide** verified code examples for natural language map interactions
## Product Features
### AI-Powered Navigation
Enables natural language interaction for map and navigation services, allowing users to control maps through voice or text commands like "Navigate to the nearest gas station".
### Seamless AMap APP Integration
Built-in LinkClient support for communication with the AMap APP, enabling cross-app navigation and data sharing.
### Multi-Transport Mode
Supports switching between driving, walking, and cycling modes with AI-driven route planning.
### Complete Lifecycle Management
Comprehensive lifecycle management guide covering initialization, scene management, state reset, and memory cleanup.
## Capabilities
### Core Features
| **Capability** | **Description** |
| --- | --- |
| Natural Language Query | Send voice/text queries for intelligent map interaction |
| Query Result Handling | Process AI responses including routes, POIs, and navigation data |
| Navigation Control | Start/stop navigation, switch routes |
| LinkClient | Communicate with AMap APP for cross-app features |
### Configuration
| **Capability** | **Description** |
| --- | --- |
| Transport Mode | Switch between driving, walking, cycling |
| Logger | Configure SDK internal logging |
| Lifecycle | Scene management, state reset, memory cleanup |
### Reference
| **Capability** | **Description** |
| --- | --- |
| Voice Commands | Supported natural language command examples |
| Core Classes | Public classes and enum reference |
| Troubleshooting | Error codes and common issue resolution |
## Quick Start
### Step 1: Configure Skill in Cursor
```bash
# Link the Android LLM Agent skill to your project
ln -s /path/to/open_sdk_skills/android-llm-agent .cursor/skills/android-llm-agent
```
### Step 2: Add Dependencies
```gradle
// LLM Agent SDK
implementation 'com.amap.lbs.client:amap-agent:1.1.41'
// Navigation SDK (Required)
implementation 'com.amap.api:navi-3dmap:latest.integration'
// Location SDK (Required)
implementation 'com.amap.api:location:latest.integration'
```
### Step 3: Verify Configuration
Open Cursor AI Chat and enter:
```text
Help me integrate the AMap LLM Agent SDK into my Android app and send a natural language query to search for nearby restaurants
```
If AI correctly references the Skill files and generates complete integration code, the Skill has been successfully loaded.
## Usage Examples
### Example 1: SDK Initialization
```text
Initialize the AMap LLM Agent SDK in my Android Application class with proper lifecycle management
```
### Example 2: Natural Language Query
```text
Send a natural language query "Navigate to Beijing Capital Airport" and handle the route planning result
```
### Example 3: LinkClient Integration
```text
Set up LinkClient to communicate with the AMap APP for cross-app navigation
```
### Example 4: Transport Mode Switch
```text
Implement a transport mode selector that allows users to switch between driving, walking, and cycling
```
## Directory Structure
```text
android-llm-agent/
├── SKILL.md # Main skill file (AI entry point)
├── api/ # API guides
│ ├── quick-start.md # Quick integration guide
│ ├── agent-query.md # Send AI queries
│ ├── query-result.md # Handle query results
│ ├── link-client.md # LinkClient communication
│ ├── transport-mode.md # Transport mode switching
│ ├── logger.md # Logger configuration
│ └── lifecycle.md # Lifecycle management
└── references/ # Reference documentation
├── core-classes.md # Core classes reference
├── troubleshooting.md # Troubleshooting guide
└── voice-commands.md # Voice command examples
```
## FAQ
### Q: Agent SDK dependency cannot be downloaded
**A:** If the Agent SDK or Navigation SDK dependency has issues (download failure, version conflicts, etc.), please contact the AMap team for the dependency package.
### Q: Natural language query returns no result
**A:** Check that:
1. SDK is properly initialized
2. Network connection is available
3. API key is correctly configured
### Q: LinkClient connection fails
**A:** Ensure:
1. AMap APP is installed on the device
2. LinkClient is properly configured
3. Required permissions are granted
## Related Links
- [AMap Open Platform Console](https://console.amap.com/)
- [Cursor Official Documentation](https://docs.cursor.com/)
- [⬆️ Back to Home](../README.md)
FILE:README_zh.md
# Android LLM Agent SDK Skills 使用文档
[⬆️ 返回首页](../README_zh.md)
## 产品介绍
**高德 Android LLM Agent SDK Skills** 是一套专为 AI IDE 设计的 AI 编程技能包。它将高德 LLM Agent SDK(Android 版)的官方文档、最佳实践和代码模板整合为结构化的技能文件,使 Cursor、Claude、Cline 等 AI Coding 工具能够:
- **精准理解**如何将 AI 智能导航助手集成到 Android 应用中
- **自动生成** SDK 初始化、查询和导航控制代码
- **主动避免**常见的依赖冲突和生命周期管理等集成问题
- **提供**经过验证的自然语言地图交互代码示例
## 产品特点
### AI 智能导航
支持自然语言交互的地图导航服务,用户可以通过语音或文字指令控制地图,如"导航到最近的加油站"。
### 无缝高德 APP 联动
内置 LinkClient 支持,可与高德 APP 通信,实现跨应用导航和数据共享。
### 多出行方式
支持驾车、步行、骑行模式切换,配合 AI 驱动的路径规划。
### 完整的生命周期管理
全面的生命周期管理指南,覆盖初始化、场景管理、状态重置和内存清理。
## 能力介绍
### 核心功能
| **能力** | **说明** |
| --- | --- |
| 自然语言查询 | 发送语音/文字查询进行智能地图交互 |
| 查询结果处理 | 处理 AI 返回的路线、POI 和导航数据 |
| 导航控制 | 开始/停止导航、切换路线 |
| LinkClient | 与高德 APP 通信实现跨应用功能 |
### 配置
| **能力** | **说明** |
| --- | --- |
| 出行方式 | 驾车、步行、骑行 |
| 日志配置 | SDK 内部日志配置 |
| 生命周期 | 场景管理、状态重置、内存清理 |
### 参考资料
| **能力** | **说明** |
| --- | --- |
| 语音指令 | 支持的自然语言指令示例 |
| 核心类 | 公共类与枚举速查 |
| 问题排查 | 错误码与常见问题解决 |
## 快速接入
### 第一步:在 Cursor 中配置 Skill
```bash
# 将 Android LLM Agent Skill 链接到您的项目
ln -s /path/to/open_sdk_skills/android-llm-agent .cursor/skills/android-llm-agent
```
### 第二步:添加依赖
```gradle
// LLM Agent SDK
implementation 'com.amap.lbs.client:amap-agent:1.1.41'
// 导航 SDK(必须)
implementation 'com.amap.api:navi-3dmap:latest.integration'
// 定位 SDK(必须,用于实时位置更新)
implementation 'com.amap.api:location:latest.integration'
```
### 第三步:验证配置
打开 Cursor AI Chat,输入:
```text
帮我将高德 LLM Agent SDK 集成到 Android 应用中,发送一个自然语言查询搜索附近的餐厅
```
如果 AI 能够正确引用 Skill 文件并生成完整的集成代码,说明 Skill 已成功加载。
## 使用示例
### 示例 1:SDK 初始化
```text
在 Android Application 类中初始化高德 LLM Agent SDK,并做好生命周期管理
```
### 示例 2:自然语言查询
```text
发送自然语言查询"导航到北京首都机场",并处理路径规划结果
```
### 示例 3:LinkClient 集成
```text
配置 LinkClient 与高德 APP 通信,实现跨应用导航
```
### 示例 4:出行方式切换
```text
实现一个出行方式选择器,允许用户在驾车、步行、骑行之间切换
```
## 目录结构
```text
android-llm-agent/
├── SKILL.md # 技能主文件(AI 入口)
├── api/ # API 使用指南
│ ├── quick-start.md # 快速接入指南
│ ├── agent-query.md # 发送 AI 查询
│ ├── query-result.md # 处理查询结果
│ ├── link-client.md # LinkClient 通信
│ ├── transport-mode.md # 出行方式切换
│ ├── logger.md # 日志配置
│ └── lifecycle.md # 生命周期管理
└── references/ # 参考资料
├── core-classes.md # 核心类参考
├── troubleshooting.md # 问题排查指南
└── voice-commands.md # 语音指令示例
```
## 常见问题
### Q:Agent SDK 依赖无法下载
**A:** 如果 Agent SDK 或导航 SDK 依赖有问题(如无法下载、版本冲突等),请联系高德相关同学获取依赖包。
### Q:自然语言查询无返回结果
**A:** 请检查:
1. SDK 是否正确初始化
2. 网络连接是否正常
3. API Key 是否正确配置
### Q:LinkClient 连接失败
**A:** 请确保:
1. 设备上已安装高德 APP
2. LinkClient 配置正确
3. 已授予所需权限
## 相关链接
- [高德开放平台控制台](https://console.amap.com/)
- [Cursor 官方文档](https://docs.cursor.com/)
- [⬆️ 返回首页](../README_zh.md)
FILE:api/agent-query.md
# 发送 AI 查询
通过 AgentClient 发送自然语言查询。
## 导入依赖
```java
import com.amap.llm.agent.api.AMapAgentQueryParam;
import com.amap.llm.agent.api.AMapAgentQueryResult;
import com.amap.llm.agent.api.AMapApi;
import com.amap.llm.agent.api.AMapConstants;
import com.amap.api.services.route.RoutePOIItem;
import java.util.List;
```
## 基础查询
```java
private void sendQuery(String queryText) {
if (mAMapApi == null || queryText == null || queryText.isEmpty()) {
return;
}
AMapAgentQueryParam param = new AMapAgentQueryParam();
param.queryText = queryText;
String sessionId = mAMapApi.getAgentClient().query(param);
Log.d(TAG, "Query sent, sessionId: " + sessionId);
}
// 使用示例
sendQuery("去颐和园");
sendQuery("帮我搜一下麦当劳");
sendQuery("开车去奥森公园需要多久");
sendQuery("离终点还有多远");
sendQuery("顺路搜下加油站");
```
## 多轮对话(带上下文)
```java
private AMapAgentQueryResult.ActionType mCurrentActionType;
private Object mCurrentPoiResult;
private List<RoutePOIItem> mRoutePOIItemList;
private void sendQueryWithContext(String queryText) {
AMapAgentQueryParam param = new AMapAgentQueryParam();
param.queryText = queryText;
// 如果是选择场景,需要填充上下文
if (mCurrentActionType == AMapAgentQueryResult.ActionType.SEARCH_POI) {
param.selectedObject = mCurrentPoiResult;
param.lastActionType = AMapAgentQueryResult.ActionType.SEARCH_POI;
// 泛搜支持打断
mAMapApi.getAgentClient().resetAgentStatus();
} else if (mCurrentActionType == AMapAgentQueryResult.ActionType.ROUTE_SEARCH) {
param.selectedObject = mRoutePOIItemList;
param.lastActionType = AMapAgentQueryResult.ActionType.ROUTE_SEARCH;
}
String sessionId = mAMapApi.getAgentClient().query(param);
}
```
## 多轮对话示例
```java
// 第一轮:搜索
sendQuery("帮我搜一下肯德基");
// 第二轮:选择结果
sendQueryWithContext("第二个");
// 第三轮:开始导航
sendQueryWithContext("导航去那里");
```
## 重置状态
```java
// 重置 Agent 状态(打断当前对话)
mAMapApi.getAgentClient().resetAgentStatus();
// 重置到指定场景
mAMapApi.getAgentClient().resetAgentScene(AMapConstants.SceneType.HOME);
```
## 相关文档
- [处理查询结果](query-result.md)
FILE:api/lifecycle.md
# 生命周期管理
正确管理 SDK 生命周期,避免内存泄漏。
## Activity 生命周期
```java
@Override
protected void onResume() {
super.onResume();
if (mAMapNaviView != null) {
mAMapNaviView.onResume();
}
}
@Override
protected void onPause() {
super.onPause();
if (mAMapNaviView != null) {
mAMapNaviView.onPause();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// 1. 停止并销毁定位
if (mAMapLocationClient != null) {
mAMapLocationClient.stopLocation();
mAMapLocationClient.onDestroy();
mAMapLocationClient = null;
}
// 2. 销毁导航视图
if (mAMapNaviView != null) {
mAMapNaviView.onDestroy();
}
// 3. 移除监听并销毁导航
if (mAMapNavi != null) {
mAMapNavi.removeAMapNaviListener(this);
mAMapNavi.destroy();
}
// 4. 销毁 SDK
if (mAMapApi != null) {
mAMapApi.destroy();
}
}
```
## 注意事项
- `onResume`/`onPause` 必须调用 `mAMapNaviView` 对应方法,需加 null 检查
- `onDestroy` 中需按顺序释放资源:定位 → 导航视图 → 导航实例 → SDK
- 销毁导航前需先调用 `removeAMapNaviListener` 移除监听
- 定位销毁后需置 null 避免重复销毁
FILE:api/link-client.md
# LinkClient 与高德 APP 通信
通过 LinkClient 实现与高德 APP 的数据同步和远程控制。
## 导入依赖
```java
import com.amap.llm.agent.api.AMapApi;
import com.amap.llm.agent.api.AMapLinkStateCallback;
import com.amap.llm.agent.api.AMapNaviInfoCallback;
import com.amap.llm.agent.api.AMapTaxiInfoCallback;
import com.amap.llm.agent.api.AgentClient;
import com.amap.llm.agent.api.LinkClient;
```
## 初始化配置
```java
private void connectToAmapApp() {
LinkClient linkClient = mAMapApi.getLinkClient();
// 1. 配置自动重连(启用重连,间隔100ms,最多2次)
linkClient.setReconnectConfig(true, 100, 2);
// 2. 设置链接状态回调
linkClient.setLinkStateCallback(new AMapLinkStateCallback() {
@Override
public void onLinkState(AMapLinkStateCallback.LinkState state) {
runOnUiThread(() -> {
switch (state) {
case CONNECTED:
Log.i(TAG, "已连接到高德APP");
// 连接成功后切换命令目标为高德APP
mAMapApi.getAgentClient().setAgentCommandDestination(
AgentClient.AgentCommandDestination.AMAP_APP);
break;
case DISCONNECTED:
Log.w(TAG, "与高德APP断开连接");
// 断开后切回本地SDK执行
mAMapApi.getAgentClient().setAgentCommandDestination(
AgentClient.AgentCommandDestination.AMAP_SDK);
break;
}
});
}
@Override
public void onLinkError(int errorCode, String errorMessage) {
Log.e(TAG, "连接错误: " + errorCode + " - " + errorMessage);
}
});
// 3. 设置导航信息回调
linkClient.setNaviInfoCallback(new AMapNaviInfoCallback() {
@Override
public void onNaviInfo(NaviInfo info) {
Log.i(TAG, "收到导航信息: 类型=" + info.type);
}
});
// 4. 设置打车信息回调
linkClient.setTaxiInfoCallback(new AMapTaxiInfoCallback() {
@Override
public void onTaxiReceived(TaxiInfo info) {
Log.i(TAG, "打车信息: " + info.toString());
}
});
// 5. 连接服务器
linkClient.connectLinkServer();
}
```
> **注意**:状态回调在子线程中触发,如需更新 UI(如按钮文字、Toast 等),必须通过 `runOnUiThread` 切换到主线程。
## 常用操作
```java
// 连接/断开服务器
mAMapApi.getLinkClient().connectLinkServer();
mAMapApi.getLinkClient().disConnectLinkServer();
// 停止导航
mAMapApi.getLinkClient().stopNavi();
// 切换路线
mAMapApi.getLinkClient().switchRoute("pathID");
// 切换播报方式(驾车)
mAMapApi.getLinkClient().switchVoiceMode(0, 2);
// 强制刷新导航信息
mAMapApi.getLinkClient().sendKeyNaviInfo();
// 跳转到应用市场下载高德APP
mAMapApi.getLinkClient().goToDownloadAmapApp();
// 开始认证
mAMapApi.getLinkClient().startAuth();
```
## 相关文档
- [快速接入](quick-start.md)
FILE:api/logger.md
# 日志配置
配置 SDK 日志输出和性能埋点。
## 配置方法
```java
mAMapContext.setLogger(new ILogger() {
@Override
public void onLog(int level, String msg) {
switch (level) {
case LOG_LEVEL_DEBUG:
Log.d(TAG, msg);
break;
case LOG_LEVEL_INFO:
Log.i(TAG, msg);
break;
case LOG_LEVEL_WARN:
Log.w(TAG, msg);
break;
case LOG_LEVEL_ERROR:
Log.e(TAG, msg);
break;
case LOG_LEVEL_FATAL:
Log.wtf(TAG, msg);
break;
case LOG_LEVEL_TRACK:
Log.i(TAG, "[TRACK] " + msg);
break;
}
}
});
// 可选:启用多路径发送
mAMapContext.setSendMultiPath(true);
```
## 日志级别说明
| 级别 | 说明 |
|-----|------|
| `LOG_LEVEL_DEBUG` | 调试信息 |
| `LOG_LEVEL_INFO` | 一般信息 |
| `LOG_LEVEL_WARN` | 警告信息 |
| `LOG_LEVEL_ERROR` | 错误信息 |
| `LOG_LEVEL_FATAL` | 致命错误 |
| `LOG_LEVEL_TRACK` | 性能埋点 |
FILE:api/query-result.md
# 处理 AI 查询结果
根据 ActionType 处理不同场景的返回结果。
## 导入依赖
```java
import com.amap.llm.agent.api.AMapAgentQueryResult;
import com.amap.llm.agent.api.PoiResultWrapper;
import com.amap.api.services.routepoisearch.RoutePOIItem;
import java.util.List;
```
## 回调处理
```java
private void handleQueryResult(AMapAgentQueryResult result) {
// 1. 检查错误
if (result.errorCode != 0) {
Log.e(TAG, "Query error: " + result.errorCode + " - " + result.errorMessage);
return;
}
// 2. 获取总结文本(注意:没有 ttsText 字段,使用 summary)
if (result.summary != null && !result.summary.isEmpty()) {
Log.d(TAG, "Summary: " + result.summary);
}
// 3. 根据 ActionType 处理(需要从 resultObj 进行类型转换)
switch (result.actionType) {
case REQUEST_ROUTE:
case REQUEST_ROUTE_NAVI:
Log.d(TAG, "路线规划完成");
// resultObj 类型: Map<Integer, AMapNaviPath>
break;
case SEARCH_POI:
case SELECT_POI_WORK_FLOW:
case SELECT_POI_WORK_FLOW_SINGLE:
if (result.resultObj instanceof PoiResultWrapper) {
PoiResultWrapper poiResult = (PoiResultWrapper) result.resultObj;
showPoiList(poiResult);
}
break;
case ROUTE_SEARCH:
if (result.resultObj instanceof List) {
@SuppressWarnings("unchecked")
List<RoutePOIItem> routePoiList = (List<RoutePOIItem>) result.resultObj;
showRoutePoiList(routePoiList);
}
break;
case COMMAND_EXIT_NAVI:
Log.d(TAG, "退出导航");
break;
case REQUEST_GUIDE_INFO:
Log.d(TAG, "请求引导信息");
break;
default:
break;
}
// 4. 保存状态用于多轮对话
mCurrentActionType = result.actionType;
}
```
## ActionType 说明
| ActionType | 说明 | resultObj 类型 |
|------------|------|---------------|
| `NONE` | 无操作 | - |
| `REQUEST_ROUTE` | 请求路线 | `Map<Integer, AMapNaviPath>` |
| `REQUEST_ROUTE_NAVI` | 行中请求路线 | `Map<Integer, AMapNaviPath>` |
| `SEARCH_POI` | POI 搜索结果 | `PoiResultWrapper` |
| `SELECT_POI_WORK_FLOW` | POI 选点工作流 | `PoiResultWrapper` |
| `SELECT_POI_WORK_FLOW_SINGLE` | 单 POI 确认 | `PoiResultWrapper` |
| `ROUTE_SEARCH` | 沿途搜索结果 | `List<RoutePOIItem>` |
| `CHANGE_OR_VIA_POI` | 行中变更 POI | - |
| `COMMAND_EXIT_NAVI` | 退出导航 | - |
| `BREAK_SESSION` | 中断会话 | - |
| `REFUSE` | 拒绝取消 | - |
| `SET_AUTO_LISTEN` | 闲聊追问 | - |
| `REQUEST_GUIDE_INFO` | 请求引导信息 | - |
## 关键字段说明
| 字段 | 类型 | 说明 |
|-----|------|------|
| `errorCode` | int | 错误码,0 表示成功 |
| `errorMessage` | String | 错误信息 |
| `sessionId` | String | 会话 ID |
| `taskId` | String | 任务 ID |
| `actionType` | ActionType | 操作类型 |
| `stateType` | StateType | 状态类型(WORKING/APPEND/END) |
| `resultType` | ResultType | 结果类型(COMMAND/SUMMARY) |
| `summary` | String | 总结文本 |
| `resultObj` | Object | 结果对象,需根据 actionType 进行类型转换 |
| `endPoiName` | String | 终点名称 |
| `viaPoiItem` | PoiItem | 途径点信息 |
## 相关文档
- [发送 AI 查询](agent-query.md)
- [常见问题诊断](../references/troubleshooting.md)
FILE:api/quick-start.md
# 快速接入 AMap LLM Agent SDK
完成 SDK 集成的完整步骤。
## 步骤 1:添加依赖
在 `build.gradle` 中添加:
```gradle
dependencies {
// LLM Agent SDK
implementation 'com.amap.lbs.client:amap-agent:1.1.41'
// 导航 SDK(必须)
implementation 'com.amap.api:navi-3dmap:latest.integration'
// 定位 SDK(必须,用于实时位置更新)
implementation 'com.amap.api:location:latest.integration'
}
```
> ⚠️ **注意**:如果 Agent SDK 或导航 SDK 依赖有问题(如无法下载、版本冲突等),请联系高德相关同学获取依赖包。
## 步骤 2:Application 初始化(可选)
Application 中可以进行全局配置,如 API Key、隐私政策等。如果这些配置已在其他地方完成,Application 可以保持空实现。
```java
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
// 以下配置根据实际需要选择性添加
// 设置 API Key(如果需要在 Application 中设置)
// AMapApi.setApiKey(this, "your_amap_api_key");
// 开启定位引擎云控控制能力(可选)
// AMapNavi.setCustomPosControlEnable(true);
// 设置隐私政策同意状态(必须在某处调用)
// NaviSetting.updatePrivacyShow(this, true, true);
// NaviSetting.updatePrivacyAgree(this, true);
}
}
```
## 步骤 3:布局文件
在布局文件中添加 `AMapNaviView`:
```xml
<com.amap.api.navi.AMapNaviView
android:id="@+id/navi_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
```
## 步骤 4:Activity 中初始化
```java
// Agent SDK 核心类
import com.amap.llm.agent.api.AMapAgentCallback;
import com.amap.llm.agent.api.AMapAgentQueryParam;
import com.amap.llm.agent.api.AMapAgentQueryResult;
import com.amap.llm.agent.api.AMapApi;
import com.amap.llm.agent.api.AMapContext;
import com.amap.llm.agent.api.AMapNaviEnv;
import com.amap.llm.agent.api.AgentClient;
import com.amap.llm.agent.api.ILogger;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.Poi;
import com.amap.api.navi.AMapNavi;
import com.amap.api.navi.AMapNaviListener;
import com.amap.api.navi.AMapNaviView;
import com.amap.api.navi.AMapNaviViewListener;
import com.amap.api.navi.enums.TransportType;
// 定位 SDK
import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
public class MainActivity extends Activity implements AMapNaviListener, AMapNaviViewListener {
private AMapApi mAMapApi;
private AMapContext mAMapContext;
private AMapNaviEnv mAMapNaviEnv;
private AMapNavi mAMapNavi;
private AMapNaviView mAMapNaviView;
// 定位相关
private AMapLocationClient mAMapLocationClient;
private AMapLocationClientOption mLocationOption;
private AMapLocationListener mAMapLocationListener = new AMapLocationListener() {
@Override
public void onLocationChanged(AMapLocation aMapLocation) {
if (mAMapApi != null) {
// 将定位结果更新给 Agent SDK
mAMapApi.getNaviClient().updateMyLocation(aMapLocation);
}
// 定位错误时打印详细信息
if (aMapLocation != null && aMapLocation.getErrorCode() != 0) {
Log.e(TAG, "定位错误: code=" + aMapLocation.getErrorCode() +
", detail=" + aMapLocation.getLocationDetail());
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 1. 初始化 AMapNaviView(必须在 setContentView 之后)
mAMapNaviView = findViewById(R.id.navi_view);
mAMapNaviView.onCreate(savedInstanceState);
mAMapNaviView.setAMapNaviViewListener(this);
// 2. 创建 API 实例
mAMapApi = AMapApi.create();
// 3. 创建上下文
mAMapContext = new AMapContext(this);
// 4. 设置日志回调(推荐)
setupLogger();
// 5. 初始化 AMapNavi
initAMapNavi();
// 6. 配置导航环境
setupNavigationEnvironment();
// 7. 初始化 SDK
mAMapApi.init(mAMapContext);
// 8. 配置 Agent 客户端
setupAgentClient();
// 9. 初始化定位 SDK(必须在 mAMapApi 初始化之后)
initLocation();
}
private void initLocation() {
try {
mAMapLocationClient = new AMapLocationClient(getApplicationContext());
mLocationOption = new AMapLocationClientOption();
// 设置定位监听
mAMapLocationClient.setLocationListener(mAMapLocationListener);
// 设置定位间隔(毫秒)
mLocationOption.setInterval(1000);
mLocationOption.setOnceLocation(false);
// 设置为高精度定位模式
mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
// 不需要逆地理信息
mLocationOption.setNeedAddress(false);
// 设置定位参数
mAMapLocationClient.setLocationOption(mLocationOption);
// 启动定位
mAMapLocationClient.startLocation();
} catch (Exception e) {
Log.e(TAG, "初始化定位 SDK 失败", e);
}
}
private void setupLogger() {
mAMapContext.setLogger(new ILogger() {
@Override
public void onLog(int level, String msg) {
switch (level) {
case ILogger.LOG_LEVEL_DEBUG:
Log.d(TAG, msg);
break;
case ILogger.LOG_LEVEL_INFO:
Log.i(TAG, msg);
break;
case ILogger.LOG_LEVEL_WARN:
Log.w(TAG, msg);
break;
case ILogger.LOG_LEVEL_ERROR:
Log.e(TAG, msg);
break;
case ILogger.LOG_LEVEL_FATAL:
Log.wtf(TAG, msg);
break;
case ILogger.LOG_LEVEL_TRACK:
Log.i(TAG, "[TRACK] " + msg);
break;
}
// 可选:将日志显示到 UI 上
// appendLog("[" + level + "] " + msg);
}
});
}
private void initAMapNavi() {
mAMapNavi = AMapNavi.getInstance(getApplicationContext());
mAMapNavi.addAMapNaviListener(this);
mAMapNavi.setUseInnerVoice(true);
}
private void setupNavigationEnvironment() {
mAMapNaviEnv = new AMapNaviEnv();
// 设置家和公司位置
Poi homePoi = new Poi("我的家", new LatLng(39.904200, 116.407396), "HOME_POI_ID");
mAMapNaviEnv.homeLocation = homePoi;
Poi workPoi = new Poi("我的公司", new LatLng(40.002577, 116.489854), "WORK_POI_ID");
mAMapNaviEnv.workLocation = workPoi;
// 设置导航类型和路径偏好
mAMapNaviEnv.transportType = TransportType.Drive;
mAMapNaviEnv.avoidCongestion = true;
mAMapNaviEnv.avoidHighway = false;
mAMapNaviEnv.avoidCost = false;
// 绑定导航实例(必须)
mAMapNaviEnv.amapNavi = mAMapNavi;
mAMapNaviEnv.amapNaviView = mAMapNaviView;
mAMapContext.setAMapNaviEnv(mAMapNaviEnv);
}
private void setupAgentClient() {
AgentClient agentClient = mAMapApi.getAgentClient();
agentClient.setAgentCallback(new AMapAgentCallback() {
@Override
public void onQueryResult(AMapAgentQueryResult result) {
handleQueryResult(result);
}
});
// AMAP_SDK: 在当前应用执行 | AMAP_APP: 发送到高德APP执行
agentClient.setAgentCommandDestination(AgentClient.AgentCommandDestination.AMAP_SDK);
}
// ==================== 生命周期管理 ====================
@Override
protected void onResume() {
super.onResume();
if (mAMapNaviView != null) {
mAMapNaviView.onResume();
}
}
@Override
protected void onPause() {
super.onPause();
if (mAMapNaviView != null) {
mAMapNaviView.onPause();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// 销毁定位
if (mAMapLocationClient != null) {
mAMapLocationClient.stopLocation();
mAMapLocationClient.onDestroy();
mAMapLocationClient = null;
}
if (mAMapNaviView != null) {
mAMapNaviView.onDestroy();
}
if (mAMapNavi != null) {
mAMapNavi.removeAMapNaviListener(this);
mAMapNavi.destroy();
}
if (mAMapApi != null) {
mAMapApi.destroy();
}
}
// ==================== AMapNaviListener 关键回调 ====================
@Override
public void onCalculateRouteSuccess(int[] ints) {
// 算路成功后自动开始导航
if (mAMapNavi != null) {
mAMapNavi.startNavi(NaviType.GPS);
}
}
@Override
public void onCalculateRouteFailure(int errorInfo) {
Log.e(TAG, "路线计算失败: " + errorInfo);
}
// 其他 AMapNaviListener 和 AMapNaviViewListener 方法需要实现
// 参考完整示例代码
}
```
## 初始化顺序说明
正确的初始化顺序非常重要:
1. **AMapNaviView.onCreate()** - 必须在 setContentView 之后立即调用
2. **AMapApi.create()** - 创建 API 实例
3. **AMapContext** - 创建上下文
4. **setLogger()** - 设置日志回调(推荐,便于调试)
5. **AMapNavi.getInstance()** - 初始化导航实例
6. **setupNavigationEnvironment()** - 配置导航环境,绑定 AMapNavi 和 AMapNaviView
7. **AMapApi.init()** - 初始化 SDK
8. **setupAgentClient()** - 配置 Agent 客户端
9. **initLocation()** - 初始化定位 SDK(必须在 mAMapApi 初始化之后,因为定位回调需要调用 mAMapApi)
## 定位 SDK 说明
定位 SDK 用于获取用户实时位置,并通过 `mAMapApi.getNaviClient().updateMyLocation(aMapLocation)` 将位置信息更新给 Agent SDK,这对于导航和位置相关的查询非常重要。
关键配置:
- **定位间隔**:默认 1000ms,可根据需求调整
- **定位模式**:使用高精度模式 `Hight_Accuracy`
- **逆地理信息**:默认关闭,如需地址信息可开启
## 下一步
- [发送 AI 查询](agent-query.md)
- [处理查询结果](query-result.md)
- [日志配置](logger.md)
FILE:api/transport-mode.md
# 切换导航模式
支持驾车、骑行、步行、电动车等导航模式切换。
## 导入依赖
```java
import com.amap.llm.agent.api.AMapApi;
import com.amap.llm.agent.api.AMapConstants;
import com.amap.llm.agent.api.AMapNaviEnv;
import com.amap.api.navi.enums.TransportType;
import com.amap.api.navi.AMapNavi;
import com.amap.api.navi.AMapNaviView;
import com.amap.api.navi.model.AMapTravelInfo;
```
## 切换方法
```java
private void switchTransportType(int transportType) {
// 1. 停止当前导航
mAMapNavi.stopNavi();
mAMapNavi.destroy();
// 2. 重新创建导航实例
mAMapNavi = AMapNavi.getInstance(getApplicationContext());
mAMapNavi.addAMapNaviListener(this);
// 3. 根据类型设置导航视图模式
if (transportType == TransportType.Ride ||
transportType == TransportType.Walk ||
transportType == TransportType.EleBike) {
mAMapNavi.setIsNaviTravelView(true);
mAMapNavi.setTravelInfo(new AMapTravelInfo(transportType));
} else {
mAMapNavi.setIsNaviTravelView(false);
}
// 4. 更新导航环境
mAMapNaviEnv.transportType = transportType;
mAMapNaviEnv.amapNavi = mAMapNavi;
mAMapNaviEnv.amapNaviView = mAMapNaviView;
mAMapApi.getNaviClient().configNaviEnv(mAMapNaviEnv);
// 5. 重置 Agent 状态
mAMapApi.getAgentClient().resetAgentScene(AMapConstants.SceneType.HOME);
}
```
## 使用示例
```java
switchTransportType(TransportType.Drive); // 驾车
switchTransportType(TransportType.Ride); // 骑行
switchTransportType(TransportType.Walk); // 步行
switchTransportType(TransportType.EleBike); // 电动车
```
## TransportType 说明
| 类型 | 说明 |
|-----|------|
| `TransportType.Drive` | 驾车导航 |
| `TransportType.Ride` | 骑行导航 |
| `TransportType.Walk` | 步行导航 |
| `TransportType.EleBike` | 电动车导航 |
FILE:references/core-classes.md
# 核心类说明
SDK 主要类和接口说明。
## 入口类
| 类名 | 说明 |
|-----|------|
| `AMapApi` | SDK 入口类,提供各客户端访问 |
| `AMapContext` | 上下文配置,包含导航环境和日志 |
## 配置类
| 类名 | 说明 |
|-----|------|
| `AMapNaviEnv` | 导航环境配置,包含位置、偏好等 |
| `Poi` | POI 点位信息 |
| `LatLng` | 经纬度坐标 |
| `AMapCarInfo` | 车辆信息 |
## 客户端
| 类名 | 说明 |
|-----|------|
| `AgentClient` | AI 助手客户端,处理自然语言查询 |
| `NaviClient` | 导航客户端,管理导航功能 |
| `LinkClient` | 链路客户端,与高德 APP 通信 |
## 查询相关
| 类名 | 说明 |
|-----|------|
| `AMapAgentQueryParam` | 查询参数 |
| `AMapAgentQueryResult` | 查询结果 |
| `AMapAgentQueryResult.ActionType` | 操作类型枚举 |
## 回调接口
| 接口 | 说明 |
|-----|------|
| `AMapAgentCallback` | Agent 查询结果回调 |
| `AMapNaviInfoCallback` | 导航信息回调 |
| `AMapLinkStateCallback` | 链接状态回调 |
| `AMapTaxiInfoCallback` | 打车信息回调 |
| `ILogger` | 日志回调接口 |
FILE:references/troubleshooting.md
# 常见问题诊断
## SDK 初始化失败
```java
private boolean checkInitialization() {
// 检查 API Key
if (TextUtils.isEmpty(getApiKey())) {
Log.e(TAG, "API Key not set");
return false;
}
// 检查网络权限
if (!hasNetworkPermission()) {
Log.e(TAG, "Network permission not granted");
return false;
}
return true;
}
```
**检查项:**
- API Key 是否正确设置
- 网络权限是否授予
- 高德地图 SDK 版本兼容性
- 查看日志中的具体错误信息
## 查询没有返回结果
```java
private void diagnoseQueryIssue(AMapAgentQueryResult result) {
Log.d(TAG, "Error code: " + result.errorCode);
Log.d(TAG, "Error message: " + result.errorMessage);
Log.d(TAG, "Session ID: " + result.sessionId);
Log.d(TAG, "Action type: " + result.actionType);
switch (result.errorCode) {
case AMapConstants.ERROR_CODE_ILLEGAL_STATUS_STR:
mAMapApi.getAgentClient().resetAgentScene(AMapConstants.SceneType.HOME);
break;
case AMapConstants.ERROR_CODE_HOME_NOT_SET:
Log.w(TAG, "请先设置家的位置");
break;
}
}
```
**检查项:**
- 查询文本格式是否正确
- 当前场景状态是否合适
- 网络连接是否正常
## 导航无法开始
**检查项:**
- 定位权限是否授予
- 定位服务是否正常
- 起终点坐标是否有效
- AMapNaviEnv 配置是否正确
## 性能问题
**优化建议:**
- 合理设置定位频率
- 及时释放大对象和回调
- 使用异步处理避免阻塞主线程
- 定期清理缓存数据
FILE:references/voice-commands.md
# 支持的语音指令
SDK 支持的自然语言指令示例。
## 导航类
| 指令示例 | 说明 |
|---------|------|
| "去颐和园" | 导航到指定地点 |
| "导航去天安门" | 导航到指定地点 |
| "开车去奥森公园" | 驾车导航 |
| "骑车去xxx" | 骑行导航 |
| "走路去xxx" | 步行导航 |
## 搜索类
| 指令示例 | 说明 |
|---------|------|
| "帮我搜一下麦当劳" | POI 搜索 |
| "附近的加油站" | 周边搜索 |
| "找个停车场" | 周边搜索 |
## 沿途搜索
| 指令示例 | 说明 |
|---------|------|
| "顺路搜下加油站" | 沿途搜索 |
| "沿途找个服务区" | 沿途搜索 |
| "路上有没有厕所" | 沿途搜索 |
## 查询类
| 指令示例 | 说明 |
|---------|------|
| "我在哪" | 当前位置 |
| "离终点还有多远" | 剩余距离 |
| "还要多久到" | 剩余时间 |
| "开车去xxx需要多久" | 路线概要 |
## 控制类
| 指令示例 | 说明 |
|---------|------|
| "结束导航" | 停止导航 |
| "切换路线" | 切换备选路线 |
## 选择类
| 指令示例 | 说明 |
|---------|------|
| "第二个" | 选择列表项 |
| "是的" | 确认操作 |
| "导航去那里" | 确认并导航 |
Map RTOS SDK - 高德地图嵌入式 Map SDK 接入助手,支持栅格/矢量 Map 地图渲染、覆盖物绘制、轨迹导航及适配器实现指南
---
name: amap-rtos-sdk
display_name: Map RTOS SDK - 高德官方嵌入式地图 SDK Skill
version: 1.0.2
description: Map RTOS SDK - 高德地图嵌入式 Map SDK 接入助手,支持栅格/矢量 Map 地图渲染、覆盖物绘制、轨迹导航及适配器实现指南
author: 高德开放平台
tags:
- 地图
- 高德
- Map
- RTOS
- 嵌入式
- SDK
- IoT
- AMap
---
# Map RTOS SDK - 高德官方嵌入式地图 SDK Skill
> RTOS 地图 SDK 接入助手 - 支持栅格/矢量地图渲染与轨迹导航
## 触发词
当用户询问以下内容时,应触发此 Skill:
### SDK 相关
- WatchSDK、RTOS地图SDK、手表地图SDK、智能硬件地图
- awk_init、awk_uninit、SDK初始化、SDK接入
### 地图相关
- awk_map、地图渲染、创建地图、销毁地图
- 瓦片、tile、栅格地图、矢量地图
- 地图缩放、地图旋转、地图中心点
- awk_map_create_view、awk_map_do_render
### 覆盖物相关
- overlay、覆盖物、点标注、线标注、面标注
- awk_map_add_overlay、awk_map_remove_overlay
- point_overlay、polyline_overlay、polygon_overlay
### 导航相关
- awk_navi、导航、轨迹导航、实时导航
- 导航回调、导航数据、转向图标
- awk_init_navi、awk_navi_data
### 适配器相关
- adapter、适配器、适配器函数、必需函数
- memory_adapter、内存适配器
- file_adapter、文件适配器
- render_adapter、渲染适配器
- network_adapter、网络适配器
- system_adapter、系统适配器
- thread_adapter、线程适配器
- tile_file_adapter、瓦片文件适配器
- AWK_CHECK_ADAPTER_FUNC、适配器检查
### iOS 相关
- iOS 集成、iOS 接入、iOS 适配器
- Objective-C、Swift 集成
- CADisplayLink、GCD、主线程
- .a 静态库、静态库引入
- Header Search Paths、Library Search Paths
### 设备与激活
- 设备激活、awk_activate_device、license
- device_id、开放平台key
### SwiftUI 与 WatchOS 相关
- SwiftUI 地图视图、GDMapView、AMapMyLocationView
- 手势处理、拖拽、单点、双击、表冠旋转
- NavigationLink、视图导航
- 视图生命周期、onAppear、onDisappear
### Demo 与示例
- WatchSDKDemo、我的地图、导航组件
- GDWatchEngine、GDMapViewModel
- 地图场景、MapScene、GDSceneParam
- 渲染回调、AMapRenderDelegate
### 坐标相关
- GCJ02、坐标系、坐标转换
- 经纬度转屏幕坐标、屏幕坐标转经纬度
- awk_map_lonlat_to_xy、awk_map_xy_to_lonlat
### 错误与问题
- 错误码、初始化失败、激活失败
- 地图不显示、渲染异常、线程问题
- 适配器错误、-200、-300、-400、-500、-600、-701、-800
- 缺失函数、未实现函数
---
## 核心能力
WatchSDK 是一个面向 RTOS 设备的轻量级地图 SDK,提供:
- **地图渲染**:栅格/矢量地图显示、缩放、旋转
- **覆盖物**:点/线/面标注
- **轨迹导航**:实时导航数据展示
- **离线地图**:离线数据下载与使用
## 快速导航
### 接入指南
| 文档 | 说明 |
|------|------|
| [快速开始](api/quick-start.md) | 5分钟完成 SDK 接入 |
| [iOS 集成](api/ios-integration.md) | iOS 平台完整接入指南 |
| [iOS Demo 指南](api/ios-demo-guide.md) | 基于 WatchSDKDemo 的功能实现参考 |
| [生命周期](api/lifecycle.md) | 初始化、激活、销毁流程 |
| [适配器](api/adapters.md) | 内存/文件/网络/渲染适配器实现 |
### API 文档
| 文档 | 说明 |
|------|------|
| [地图操作](api/map-operations.md) | 创建、控制、渲染地图 |
| [覆盖物](api/overlays.md) | 点/线/面覆盖物管理 |
| [导航](api/navigation.md) | 导航初始化与数据回调 |
### 参考资料
| 文档 | 说明 |
|------|------|
| [适配器必需函数](references/adapter-requirements.md) | 必须实现的适配器函数与错误码 |
| [核心类型](references/core-types.md) | 关键数据结构定义 |
| [错误码](references/error-codes.md) | 错误码说明与排查 |
| [常见问题](references/troubleshooting.md) | FAQ 与问题排查 |
## 关键约束
1. **单线程模型**:所有 SDK 方法必须在同一主流程线程调用
2. **坐标系**:统一使用 GCJ02 坐标系
3. **激活要求**:首次使用需联网激活设备
## 头文件引用
```c
#include "awk.h" // 核心初始化
#include "awk_adapter.h" // 适配器定义
#include "map/awk_map.h" // 地图操作
#include "navi/awk_navi.h" // 导航功能
```
---
## 🔧 代码实现规范
### 核心原则:以 SDK 头文件为唯一真理来源
在实现任何 SDK 相关代码时,**必须**遵循以下流程:
### 1. 实现前必读头文件
**在编写任何使用 SDK 类型、函数、枚举的代码前,必须先使用 `read_file` 工具读取相关头文件,确认:**
- ✅ 结构体的完整定义和所有字段名称
- ✅ 枚举值的完整名称(包括前缀、下划线等)
- ✅ 函数签名的完整参数列表和类型
- ✅ 回调函数的签名和参数顺序
**禁止行为:**
- ❌ 根据经验或猜测假设字段名称
- ❌ 使用简写或不完整的枚举值名称
- ❌ 假设结构体包含某些"常见"字段
- ❌ 复制其他项目的代码而不验证类型定义
### 2. 关键头文件清单
实现代码时必须查阅的头文件:
| 头文件 | 用途 | 何时查阅 |
|--------|------|----------|
| `awk_defines.h` | 基础类型定义(点、矩形、位图等) | 使用 `awk_point_t`、`awk_bitmap_t`、`awk_rect_area_t` 等类型时 |
| `awk_adapter.h` | 适配器接口定义 | 实现任何适配器函数时 |
| `map/awk_map_defines.h` | 地图相关类型定义 | 使用地图参数、覆盖物、瓦片样式等时 |
| `map/awk_map.h` | 地图操作 API | 调用地图创建、渲染等函数时 |
| `navi/awk_navi_defines.h` | 导航相关类型 | 使用导航数据结构时 |
| `navi/awk_navi.h` | 导航操作 API | 调用导航相关函数时 |
### 3. 类型使用检查清单
在使用任何 SDK 类型前,必须确认:
#### 结构体字段
```
□ 已读取头文件确认结构体定义
□ 字段名称与头文件完全一致(包括大小写、下划线)
□ 字段类型正确(指针、枚举、嵌套结构体等)
□ 理解字段的语义和使用方式
```
#### 枚举值
```
□ 已读取头文件确认枚举定义
□ 使用完整的枚举值名称(不使用简写)
□ 枚举值前缀正确(如 AWK_MAP_TILE_STYLE_)
□ 注意下划线的位置(如 RGBA_8888 不是 RGBA8888)
□ 严禁根据命名规律猜测枚举值名称
```
**⚠️ 枚举值命名陷阱警告:**
SDK 中的枚举值命名**不遵循统一规则**,必须逐个查阅头文件确认。以下是常见的命名陷阱:
| 错误示例 | 正确名称 | 头文件位置 |
|---------|---------|-----------|
| ❌ `AWK_MAP_TILE_LOAD_MODE_ONLINE` | ✅ `AWK_MAP_TILE_LOAD_ONLINE` | `map/awk_map_defines.h` |
| ❌ `AWK_MAP_TILE_LOAD_MODE_OFFLINE` | ✅ `AWK_MAP_TILE_LOAD_OFFLINE` | `map/awk_map_defines.h` |
| ❌ `AWK_MAP_TILE_STYLE_NORMAL` | ✅ `AWK_MAP_TILE_STYLE_STANDARD_GRID` | `map/awk_map_defines.h` |
| ❌ `AWK_PIXEL_MODE_RGBA8888` | ✅ `AWK_PIXEL_MODE_RGBA_8888` | `awk_defines.h` |
**关键规则:**
1. **绝对禁止**根据其他枚举的命名规律推测新枚举的名称
2. **绝对禁止**使用"常见"或"标准"的命名假设
3. **必须**使用 `read_file` 工具读取对应头文件确认枚举定义
4. **必须**复制粘贴头文件中的完整枚举值名称,不要手动输入
#### 函数调用
```
□ 已读取头文件确认函数签名
□ 参数数量正确
□ 参数类型匹配
□ 参数顺序正确
□ 理解返回值的含义
```
### 4. 实现流程示例
**正确的实现流程:**
```
步骤 1: 确定需要使用的类型/函数
↓
步骤 2: 使用 read_file 读取相关头文件
↓
步骤 3: 仔细阅读类型定义和注释
↓
步骤 4: 按照头文件定义编写代码
↓
步骤 5: 再次对照头文件检查代码
```
**示例 1:实现网络适配器(结构体字段)**
```objc
// ❌ 错误做法:直接编写代码
static uint64_t aw_network_send(awk_http_request_t *request, ...) {
// 假设 request->body 是 char*
urlRequest.HTTPBody = [NSData dataWithBytes:request->body
length:request->body_size];
}
// ✅ 正确做法:先读取 awk_adapter.h 确认结构体定义
// 1. read_file("awk_adapter.h") 查看 awk_http_request_t 定义
// 2. 发现 body 是 awk_http_buffer_t* 类型
// 3. 再查看 awk_http_buffer_t 定义
// 4. 按照实际定义编写代码
static uint64_t aw_network_send(awk_http_request_t *request, ...) {
// 正确:使用 request->body->buffer 和 request->body->length
if (request->body && request->body->buffer && request->body->length > 0) {
urlRequest.HTTPBody = [NSData dataWithBytes:request->body->buffer
length:request->body->length];
}
}
```
**示例 2:使用枚举值(最常见错误)**
```objc
// ❌ 错误做法:根据命名规律猜测
awk_context_t context;
context.tile_load_mode = AWK_MAP_TILE_LOAD_MODE_ONLINE; // 编译错误!
context.tile_style = AWK_MAP_TILE_STYLE_NORMAL; // 编译错误!
// ✅ 正确做法:先读取 map/awk_map_defines.h 确认枚举定义
// 1. read_file("map/awk_map_defines.h")
// 2. 搜索 "awk_map_tile_load_mode_t" 找到枚举定义:
// typedef enum {
// AWK_MAP_TILE_LOAD_OFFLINE = 0x01,
// AWK_MAP_TILE_LOAD_ONLINE = 0x02 // ← 注意:不是 MODE_ONLINE
// } awk_map_tile_load_mode_t;
// 3. 搜索 "awk_map_tile_style_t" 找到枚举定义:
// typedef enum {
// AWK_MAP_TILE_STYLE_STANDARD_GRID = 0, // ← 注意:不是 NORMAL
// AWK_MAP_TILE_SATELLITE = 1,
// ...
// } awk_map_tile_style_t;
// 4. 复制粘贴正确的枚举值
awk_context_t context;
context.tile_load_mode = AWK_MAP_TILE_LOAD_ONLINE; // ✅ 正确
context.tile_style = AWK_MAP_TILE_STYLE_STANDARD_GRID; // ✅ 正确
```
### 5. 常见错误模式及预防
| 错误模式 | 预防方法 | 实际案例 |
|---------|---------|---------|
| 字段名称错误(如 `data` vs `buffer`) | 读取头文件确认字段名 | `request->body` 实际是 `awk_http_buffer_t*` 类型 |
| **枚举值名称错误** | **必须读取头文件确认完整枚举值** | **`AWK_MAP_TILE_LOAD_MODE_ONLINE` ❌ 应为 `AWK_MAP_TILE_LOAD_ONLINE` ✅** |
| 枚举值前缀不一致 | 不要根据命名规律猜测 | `AWK_MAP_TILE_STYLE_NORMAL` ❌ 应为 `AWK_MAP_TILE_STYLE_STANDARD_GRID` ✅ |
| 结构体字段不存在(如 `center`、`zoom`) | 读取头文件确认结构体定义 | `awk_context_t` 中没有 `center` 字段 |
| 回调函数签名错误 | 读取头文件确认函数指针定义 | 回调参数顺序和类型必须完全匹配 |
| 类型嵌套错误(如 `body` 是指针) | 读取头文件理解类型层次 | `request->body->buffer` 而非 `request->body` |
| **字段名拼写错误** | **必须读取头文件确认字段名** | **`fill_style` ❌ 应为 `fill_ttyle` ✅(头文件拼写错误)** |
**🚨 枚举值错误是最常见的编译错误,必须严格遵守以下流程:**
```
步骤 1: 确定需要使用的枚举类型(如 tile_load_mode)
↓
步骤 2: 使用 read_file 读取对应头文件(如 map/awk_map_defines.h)
↓
步骤 3: 搜索枚举类型定义(如 awk_map_tile_load_mode_t)
↓
步骤 4: 复制粘贴完整的枚举值名称(如 AWK_MAP_TILE_LOAD_ONLINE)
↓
步骤 5: 绝不手动输入或根据规律猜测
```
---
## 🎨 渲染适配器实现指南
渲染适配器是 WatchSDK 中**最关键**的适配器,负责将地图内容绘制到屏幕上。如果渲染适配器实现为空或不正确,地图将无法显示。
### 1. 渲染适配器核心职责
渲染适配器需要实现 9 个回调函数:
| 函数 | 职责 | 是否必需 |
|------|------|---------|
| `begin_drawing` | 开始绘制,创建图形上下文 | ✅ 必需 |
| `commit_drawing` | 结束绘制,提交渲染结果 | ✅ 必需 |
| `draw_bitmap` | 绘制位图(地图瓦片) | ✅ 必需 |
| `draw_point` | 绘制点(覆盖物) | 可选 |
| `draw_polyline` | 绘制线(覆盖物) | 可选 |
| `draw_polygon` | 绘制面(覆盖物) | 可选 |
| `draw_text` | 绘制文字(标注) | 可选 |
| `draw_color` | 绘制纯色背景 | 可选 |
| `measure_text` | 测量文字尺寸 | ✅ 必需 |
### 2. 实现前必读的头文件
```c
#include "awk_adapter.h" // 渲染适配器接口定义
#include "awk_defines.h" // 基础类型定义
```
**关键类型定义:**
```c
// 渲染上下文(注意:没有 scale 字段)
typedef struct _awk_render_context_t {
int32_t width; // 画布宽度
int32_t height; // 画布高度
awk_rect_area_t map_view_rect; // 地图view的rect区域
} awk_render_context_t;
// 绘制样式(注意:字段名是 fill_ttyle,不是 fill_style)
typedef struct _awk_paint_style_t {
uint32_t width; // 画笔宽度
uint32_t color; // 画笔颜色 ARGB
float angle; // 旋转角度
awk_text_style_t text_style; // 文字样式
awk_fill_style_t fill_ttyle; // ⚠️ 注意拼写:fill_ttyle
awk_dash_style_t dash_style; // 虚线样式
} awk_paint_style_t;
// 填充样式枚举
typedef enum {
AWK_FILL_STYLE_DRAWING_ONLY, // 仅填充
AWK_FILL_STYLE_DRAWING_AND_STROKE, // 填充+描边
AWK_FILL_STYLE_STROKE_ONLY // 仅描边
} awk_fill_style_t;
```
### 3. iOS 平台实现要点
#### 3.1 全局状态管理
```objc
// 全局渲染上下文存储
static NSMutableDictionary<NSNumber*, NSValue*> *g_renderContexts = nil;
static NSMutableDictionary<NSNumber*, UIImage*> *g_renderedImages = nil;
typedef struct {
int32_t width;
int32_t height;
} RenderContext;
```
#### 3.2 begin_drawing 实现
**关键点:**
- 创建 UIKit 图形上下文
- 保存渲染上下文信息
- ⚠️ 注意:`awk_render_context_t` 中**没有 scale 字段**
```objc
static void aw_begin_drawing(uint32_t map_id, awk_render_context_t context) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
g_renderContexts = [NSMutableDictionary dictionary];
g_renderedImages = [NSMutableDictionary dictionary];
});
// 保存渲染上下文
RenderContext renderCtx;
renderCtx.width = context.width;
renderCtx.height = context.height;
NSValue *value = [NSValue valueWithBytes:&renderCtx objCType:@encode(RenderContext)];
g_renderContexts[@(map_id)] = value;
// 创建图形上下文(scale 使用固定值 1.0)
CGSize size = CGSizeMake(context.width, context.height);
UIGraphicsBeginImageContextWithOptions(size, NO, 1.0);
NSLog(@"[Render] Begin drawing for map %d, size: %dx%d", map_id, context.width, context.height);
}
```
#### 3.3 commit_drawing 实现
**关键点:**
- 从图形上下文获取渲染的 UIImage
- 通过 NSNotification 通知主线程更新 UI
- 结束图形上下文
```objc
static void aw_commit_drawing(uint32_t map_id) {
// 获取渲染的图像
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
if (image) {
g_renderedImages[@(map_id)] = image;
NSLog(@"[Render] Commit drawing for map %d, image size: %.0fx%.0f",
map_id, image.size.width, image.size.height);
// 通知主线程更新 UI
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:@"WatchSDKMapRendered"
object:nil
userInfo:@{@"mapId": @(map_id), @"image": image}];
});
}
}
```
#### 3.4 draw_bitmap 实现(最关键)
**关键点:**
- 创建 CGBitmapContext 处理位图数据
- **坐标系转换**:SDK 使用标准坐标系(原点在左下),iOS 使用左上坐标系
- 支持旋转角度
- 正确释放内存
```objc
static void aw_draw_bitmap(uint32_t map_id, awk_rect_area_t area, awk_bitmap_t bitmap, const awk_paint_style_t *style) {
if (!bitmap.buffer || bitmap.width == 0 || bitmap.height == 0) return;
CGContextRef context = UIGraphicsGetCurrentContext();
if (!context) return;
// 获取渲染上下文
NSValue *value = g_renderContexts[@(map_id)];
if (!value) return;
RenderContext renderCtx;
[value getValue:&renderCtx];
// 创建位图上下文
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
size_t bitsPerComponent = 8;
uint32_t alphaInfo = bitmap.pre_multiplied ? kCGImageAlphaPremultipliedLast : kCGImageAlphaLast;
CGContextRef bitmapContext = CGBitmapContextCreate(
(void*)bitmap.buffer,
bitmap.width,
bitmap.height,
bitsPerComponent,
bitmap.width * 4, // bytesPerRow (RGBA = 4 bytes)
colorSpace,
alphaInfo
);
if (!bitmapContext) {
CGColorSpaceRelease(colorSpace);
return;
}
CGImageRef imageRef = CGBitmapContextCreateImage(bitmapContext);
// 🔑 关键:坐标系转换
// SDK 使用标准坐标系(原点在左下),iOS 使用左上坐标系
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0, renderCtx.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGRect targetRect = CGRectMake(area.x, renderCtx.height - area.y - area.height, area.width, area.height);
// 处理旋转
if (style && style->angle != 0) {
CGFloat centerX = targetRect.origin.x + area.width / 2.0;
CGFloat centerY = targetRect.origin.y + area.height / 2.0;
CGContextTranslateCTM(context, centerX, centerY);
CGContextRotateCTM(context, style->angle * M_PI / 180.0);
CGContextDrawImage(context, CGRectMake(-area.width / 2.0, -area.height / 2.0, area.width, area.height), imageRef);
CGContextRotateCTM(context, -style->angle * M_PI / 180.0);
CGContextTranslateCTM(context, -centerX, -centerY);
} else {
CGContextDrawImage(context, targetRect, imageRef);
}
CGContextRestoreGState(context);
// 释放内存
CGImageRelease(imageRef);
CGContextRelease(bitmapContext);
CGColorSpaceRelease(colorSpace);
}
```
#### 3.5 辅助函数
```objc
// ARGB 颜色转 UIColor
static UIColor* UIColorFromARGB(uint32_t argb) {
CGFloat alpha = ((argb >> 24) & 0xFF) / 255.0;
CGFloat red = ((argb >> 16) & 0xFF) / 255.0;
CGFloat green = ((argb >> 8) & 0xFF) / 255.0;
CGFloat blue = (argb & 0xFF) / 255.0;
return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
}
```
#### 3.6 draw_point 实现
**⚠️ 注意:字段名是 `fill_ttyle`,不是 `fill_style`**
```objc
static void aw_draw_point(uint32_t map_id, awk_point_t *points, uint32_t point_size, const awk_paint_style_t *style) {
if (!points || point_size == 0 || !style) return;
CGContextRef context = UIGraphicsGetCurrentContext();
if (!context) return;
UIColor *color = UIColorFromARGB(style->color);
[color set];
for (uint32_t i = 0; i < point_size; i++) {
awk_point_t point = points[i];
CGFloat radius = style->width / 2.0;
// ⚠️ 使用 fill_ttyle,不是 fill_style
if (style->fill_ttyle == AWK_FILL_STYLE_DRAWING_ONLY ||
style->fill_ttyle == AWK_FILL_STYLE_DRAWING_AND_STROKE) {
CGContextAddArc(context, point.x, point.y, radius, 0, 2 * M_PI, 0);
CGContextFillPath(context);
}
if (style->fill_ttyle == AWK_FILL_STYLE_STROKE_ONLY ||
style->fill_ttyle == AWK_FILL_STYLE_DRAWING_AND_STROKE) {
CGContextSetLineWidth(context, 2.0);
CGContextAddArc(context, point.x, point.y, radius + 1, 0, 2 * M_PI, 0);
CGContextStrokePath(context);
}
}
}
```
#### 3.7 draw_polyline 实现
**⚠️ 注意:`awk_paint_style_t` 中没有 `cap_style` 字段**
```objc
static void aw_draw_polyline(uint32_t map_id, awk_point_t *points, uint32_t point_size, const awk_paint_style_t *style) {
if (!points || point_size < 2 || !style) return;
CGContextRef context = UIGraphicsGetCurrentContext();
if (!context) return;
UIColor *color = UIColorFromARGB(style->color);
[color set];
CGContextSetLineWidth(context, style->width);
CGContextSetLineCap(context, kCGLineCapRound); // 固定使用圆角
// 设置虚线样式
if (style->dash_style.painted_length > 0 || style->dash_style.unpainted_length > 0) {
CGFloat lengths[] = {style->dash_style.painted_length, style->dash_style.unpainted_length};
CGContextSetLineDash(context, style->dash_style.offset, lengths, 2);
}
CGContextBeginPath(context);
CGContextMoveToPoint(context, points[0].x, points[0].y);
for (uint32_t i = 1; i < point_size; i++) {
CGContextAddLineToPoint(context, points[i].x, points[i].y);
}
CGContextStrokePath(context);
// 重置虚线样式
CGContextSetLineDash(context, 0, NULL, 0);
}
```
### 4. UI 层集成
在 ViewController 中接收渲染结果:
```objc
@interface MapViewController ()
@property (nonatomic, strong) UIImageView *mapImageView;
@end
@implementation MapViewController
- (void)setupUI {
// 创建地图图像视图
self.mapImageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
self.mapImageView.contentMode = UIViewContentModeScaleAspectFit;
[self.view addSubview:self.mapImageView];
// 监听地图渲染完成通知
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(onMapRendered:)
name:@"WatchSDKMapRendered"
object:nil];
}
- (void)onMapRendered:(NSNotification *)notification {
NSDictionary *userInfo = notification.userInfo;
NSNumber *mapId = userInfo[@"mapId"];
UIImage *image = userInfo[@"image"];
if (mapId.intValue == self.mapId && image) {
self.mapImageView.image = image;
NSLog(@"[MapViewController] Map rendered and displayed");
}
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end
```
### 5. 常见渲染问题排查
| 问题 | 原因 | 解决方案 |
|------|------|---------|
| 地图不显示 | 渲染适配器未实现或实现为空 | 实现完整的 `begin_drawing`、`commit_drawing`、`draw_bitmap` |
| 编译错误:`fill_style` 不存在 | 字段名拼写错误 | 使用 `fill_ttyle`(头文件中的拼写) |
| 编译错误:`scale` 不存在 | `awk_render_context_t` 中没有此字段 | 使用固定值 1.0 或从其他地方获取 |
| 编译错误:`cap_style` 不存在 | `awk_paint_style_t` 中没有此字段 | 使用固定值 `kCGLineCapRound` |
| 地图倒置 | 坐标系未转换 | 使用 `CGContextTranslateCTM` 和 `CGContextScaleCTM` 转换 |
| 内存泄漏 | 未释放 CGContext 和 CGImage | 调用 `CGContextRelease` 和 `CGImageRelease` |
### 6. 渲染适配器实现检查清单
```
□ 已读取 awk_adapter.h 确认所有回调函数签名
□ 已读取 awk_defines.h 确认基础类型定义
□ 实现了 begin_drawing(创建图形上下文)
□ 实现了 commit_drawing(提交渲染结果)
□ 实现了 draw_bitmap(绘制地图瓦片)
□ 实现了 measure_text(测量文字尺寸)
□ 正确处理了坐标系转换
□ 使用了正确的字段名(fill_ttyle 而非 fill_style)
□ 没有使用不存在的字段(scale、cap_style)
□ 正确释放了所有 CGContext 和 CGImage
□ 通过通知机制将渲染结果传递给 UI 层
```
---
## 📚 参考资料
### 完整示例代码
完整的渲染适配器实现可参考以下关键文件结构:
**iOS 平台适配器实现:**
```
项目根目录/
├── SDK/
│ ├── WatchSDKAdapters.h // 适配器头文件
│ ├── WatchSDKAdapters.m // 适配器实现(包含渲染适配器)
│ └── WatchSDKManager.h/m // SDK 管理器
└── ViewControllers/
└── MapViewController.m // UI 层集成示例
```
**关键实现文件说明:**
- **适配器实现文件**:包含所有 6 个适配器的完整实现(内存、文件、系统、网络、渲染、线程)
- **SDK 管理器**:封装 SDK 初始化、激活、地图创建等操作
- **UI 集成文件**:展示如何接收渲染结果并显示地图
### 相关文档
- [适配器必需函数](references/adapter-requirements.md)
- [iOS 集成指南](api/ios-integration.md)
- [常见问题排查](references/troubleshooting.md)
// ❌ 错误做法:根据命名规律猜测
awk_context_t context;
context.tile_load_mode = AWK_MAP_TILE_LOAD_MODE_ONLINE; // 编译错误!
context.tile_style = AWK_MAP_TILE_STYLE_NORMAL; // 编译错误!
// ✅ 正确做法:先读取 map/awk_map_defines.h 确认枚举定义
// 1. read_file("map/awk_map_defines.h")
// 2. 搜索 "awk_map_tile_load_mode_t" 找到枚举定义:
// typedef enum {
// AWK_MAP_TILE_LOAD_OFFLINE = 0x01,
// AWK_MAP_TILE_LOAD_ONLINE = 0x02 // ← 注意:不是 MODE_ONLINE
// } awk_map_tile_load_mode_t;
// 3. 搜索 "awk_map_tile_style_t" 找到枚举定义:
// typedef enum {
// AWK_MAP_TILE_STYLE_STANDARD_GRID = 0, // ← 注意:不是 NORMAL
// AWK_MAP_TILE_SATELLITE = 1,
// ...
// } awk_map_tile_style_t;
// 4. 复制粘贴正确的枚举值
awk_context_t context;
context.tile_load_mode = AWK_MAP_TILE_LOAD_ONLINE; // ✅ 正确
context.tile_style = AWK_MAP_TILE_STYLE_STANDARD_GRID; // ✅ 正确
```
### 5. 常见错误模式及预防
| 错误模式 | 预防方法 | 实际案例 |
|---------|---------|---------|
| 字段名称错误(如 `data` vs `buffer`) | 读取头文件确认字段名 | `request->body` 实际是 `awk_http_buffer_t*` 类型 |
| **枚举值名称错误** | **必须读取头文件确认完整枚举值** | **`AWK_MAP_TILE_LOAD_MODE_ONLINE` ❌ 应为 `AWK_MAP_TILE_LOAD_ONLINE` ✅** |
| 枚举值前缀不一致 | 不要根据命名规律猜测 | `AWK_MAP_TILE_STYLE_NORMAL` ❌ 应为 `AWK_MAP_TILE_STYLE_STANDARD_GRID` ✅ |
| 结构体字段不存在(如 `center`、`zoom`) | 读取头文件确认结构体定义 | `awk_context_t` 中没有 `center` 字段 |
| 回调函数签名错误 | 读取头文件确认函数指针定义 | 回调参数顺序和类型必须完全匹配 |
| 类型嵌套错误(如 `body` 是指针) | 读取头文件理解类型层次 | `request->body->buffer` 而非 `request->body` |
**🚨 枚举值错误是最常见的编译错误,必须严格遵守以下流程:**
```
步骤 1: 确定需要使用的枚举类型(如 tile_load_mode)
↓
步骤 2: 使用 read_file 读取对应头文件(如 map/awk_map_defines.h)
↓
步骤 3: 搜索枚举类型定义(如 awk_map_tile_load_mode_t)
↓
步骤 4: 复制粘贴完整的枚举值名称(如 AWK_MAP_TILE_LOAD_ONLINE)
↓
步骤 5: 绝不手动输入或根据规律猜测
```
### 6. 架构兼容性检查
在 iOS 项目中集成静态库时,必须检查架构兼容性:
```bash
# 检查静态库支持的架构
lipo -info libWatchSDK.a
# 如果库是 x86_64,需要在项目配置中排除 arm64
# Build Settings → Excluded Architectures → arm64
```
### 7. 编译前自检
在提交代码或编译前,进行以下检查:
```
□ 所有使用的类型都已查阅头文件
□ 所有字段名称与头文件一致
□ 所有枚举值使用完整名称
□ 所有函数调用参数正确
□ 静态库架构与编译目标匹配
□ 没有假设或猜测的代码
```
---
## 📝 实现检查表
在完成 SDK 集成代码后,使用此检查表验证:
### 适配器实现
- [ ] 已读取 `awk_adapter.h` 确认所有适配器函数签名
- [ ] 所有回调函数的参数类型和顺序正确
- [ ] 结构体字段访问使用正确的字段名
- [ ] 枚举值使用完整名称
### 地图操作
- [ ] 已读取 `map/awk_map_defines.h` 确认参数结构体定义
- [ ] `awk_map_view_param_t` 只使用存在的字段
- [ ] 瓦片样式枚举值完整正确
- [ ] 像素模式枚举值包含下划线
### 类型使用
- [ ] 已读取 `awk_defines.h` 确认基础类型定义
- [ ] `awk_bitmap_t` 使用 `buffer` 字段而非 `data`
- [ ] `awk_paint_style_t` 使用 `color` 字段而非 `fill_color`
- [ ] 所有指针类型正确解引用
### 编译配置
- [ ] 已检查静态库架构(`lipo -info`)
- [ ] 项目配置排除不支持的架构
- [ ] Header Search Paths 正确配置
- [ ] Library Search Paths 正确配置
---
## 🎯 总结
**核心原则:永远以 SDK 头文件为准,不要假设任何类型定义。**
在实现任何 SDK 相关代码时:
1. **先读头文件** - 使用 `read_file` 工具
2. **确认定义** - 仔细阅读类型定义和注释
3. **按定义编写** - 严格按照头文件定义编写代码
4. **再次检查** - 对照头文件检查代码正确性
这样可以从根本上避免类型不匹配、字段不存在等编译错误。
FILE:README.md
# RTOS Map SDK Skills User Guide
[🇨🇳 中文文档](./README_zh.md) | [⬆️ Back to Home](../README.md)
## Product Introduction
**AMap RTOS Map SDK Skills** (WatchSDK) is an AI programming skill package designed for AI IDEs. It integrates the official documentation, best practices, and code templates of the AMap RTOS Map SDK into structured skill files, enabling AI coding tools like Cursor, Claude, and Cline to:
- **Accurately understand** how to integrate and use the WatchSDK on RTOS devices
- **Automatically generate** adapter implementations and map integration code
- **Proactively avoid** common pitfalls such as incorrect enum names, missing struct fields, and thread safety issues
- **Provide** verified code examples with strict type checking against SDK header files
## Product Features
### Lightweight Map SDK
Designed specifically for smart glasses, smart watches and other RTOS devices, providing raster and vector map rendering with minimal resource footprint.
### Strict Type Safety
Built-in code implementation guidelines that enforce reading SDK header files before writing code, preventing common compilation errors from incorrect enum values or struct field names.
### Complete Adapter Guide
Comprehensive adapter implementation documentation covering memory, file, network, render, system, and thread adapters with platform-specific examples.
### iOS Integration Support
Detailed iOS integration guide including SwiftUI views, gesture handling, and complete demo project references.
## Capabilities
### Map Rendering
| **Capability** | **Description** |
| --- | --- |
| Map Initialization | SDK init, device activation, map creation |
| Raster/Vector Maps | Standard grid and satellite tile styles |
| View Control | Zoom, rotation, center point adjustment |
| Lifecycle Management | Init, activate, create, render, destroy flow |
### Overlays
| **Capability** | **Description** |
| --- | --- |
| Point Overlay | Point annotations on map |
| Polyline Overlay | Line annotations for routes and tracks |
| Polygon Overlay | Area annotations |
| Overlay Management | Add, remove, update overlays |
### Navigation
| **Capability** | **Description** |
| --- | --- |
| Track Navigation | Real-time navigation data display |
| Navigation Callbacks | Turn-by-turn data, distance, ETA |
| Turn Icons | Navigation turn direction icons |
### Platform Adapters
| **Capability** | **Description** |
| --- | --- |
| Memory Adapter | malloc/free/realloc implementations |
| File Adapter | File I/O operations |
| Network Adapter | HTTP request handling |
| Render Adapter | Map rendering to screen (most critical) |
| System Adapter | System time, device info |
| Thread Adapter | Thread creation and synchronization |
## Quick Start
### Step 1: Configure Skill in Cursor
```bash
# Link the RTOS skill to your project
ln -s /path/to/open_sdk_skills/RTOS .cursor/skills/RTOS
```
### Step 2: Verify Configuration
Open Cursor AI Chat and enter:
```text
Help me initialize the WatchSDK and create a map view, implementing all required adapters for iOS platform
```
If AI correctly references the RTOS Skill files and generates code with proper header file type checking, the Skill has been successfully loaded.
### Step 3: Key Integration Points
1. **Initialize SDK** with `awk_init()` - see [Quick Start](api/quick-start.md)
2. **Implement Adapters** - see [Adapters Guide](api/adapters.md)
3. **Activate Device** with `awk_activate_device()` - see [Lifecycle](api/lifecycle.md)
4. **Create Map** with `awk_map_create_view()` - see [Map Operations](api/map-operations.md)
## Usage Examples
### Example 1: SDK Initialization
```text
Initialize WatchSDK with all required adapters for iOS, including memory, file, network, render, system, and thread adapters
```
### Example 2: Map Creation
```text
Create a map view centered on Beijing with zoom level 12, using standard grid tile style
```
### Example 3: Add Overlays
```text
Add a polyline overlay on the map showing a navigation route from point A to point B
```
### Example 4: Navigation Integration
```text
Initialize navigation module and set up callbacks to receive real-time navigation data including turn directions and remaining distance
```
## Directory Structure
```text
RTOS/
├── SKILL.md # Main skill file (AI entry point)
├── api/ # API guides
│ ├── quick-start.md # Quick SDK integration
│ ├── ios-integration.md # iOS platform integration
│ ├── ios-demo-guide.md # iOS demo project guide
│ ├── lifecycle.md # Init, activate, destroy flow
│ ├── adapters.md # Adapter implementation guide
│ ├── map-operations.md # Map creation and control
│ ├── overlays.md # Overlay management
│ └── navigation.md # Navigation setup
└── references/ # Reference documentation
├── adapter-requirements.md # Required adapter functions
├── core-types.md # Key data structure definitions
├── error-codes.md # Error codes and troubleshooting
└── troubleshooting.md # FAQ and problem diagnosis
```
## Key Constraints
1. **Single-Thread Model**: All SDK methods must be called on the same main thread
2. **Coordinate System**: Uses GCJ02 coordinate system exclusively
3. **Activation Required**: First-time use requires network activation
4. **Header File First**: Always read SDK header files before writing integration code
## FAQ
### Q: Map shows blank/nothing renders
**A:** Check that the render adapter is fully implemented. The three critical functions are `begin_drawing`, `commit_drawing`, and `draw_bitmap`. Empty implementations will result in no map display.
### Q: Compilation errors with enum values
**A:** SDK enum naming is inconsistent. Always read the header file to confirm exact enum names. For example, use `AWK_MAP_TILE_LOAD_ONLINE` not `AWK_MAP_TILE_LOAD_MODE_ONLINE`.
### Q: Compilation errors with struct fields
**A:** Some struct fields have unusual naming (e.g., `fill_ttyle` instead of `fill_style`). Always verify field names against the header file definitions.
## Related Links
- [AMap Open Platform Console](https://console.amap.com/)
- [Cursor Official Documentation](https://docs.cursor.com/)
- [⬆️ Back to Home](../README.md)
FILE:README_zh.md
# RTOS 地图 SDK Skills 使用文档
[⬆️ 返回首页](../README_zh.md)
## 产品介绍
**高德 RTOS 地图 SDK Skills**(WatchSDK)是一套专为 AI IDE 设计的 AI 编程技能包。它将高德 RTOS 地图 SDK 的官方文档、最佳实践和代码模板整合为结构化的技能文件,使 Cursor、Claude、Cline 等 AI Coding 工具能够:
- **精准理解**如何在 RTOS 设备上集成和使用 WatchSDK
- **自动生成**适配器实现和地图集成代码
- **主动避免**常见的枚举命名错误、结构体字段缺失和线程安全等陷阱
- **提供**经过严格类型检查的代码示例
## 产品特点
### 轻量级地图 SDK
专为智能眼镜、智能手表等 RTOS 设备设计,以最小的资源占用提供栅格和矢量地图渲染能力。
### 严格的类型安全
内置代码实现规范,强制要求在编写代码前读取 SDK 头文件,从根本上避免枚举值错误、结构体字段不存在等编译错误。
### 完整的适配器指南
全面的适配器实现文档,覆盖内存、文件、网络、渲染、系统和线程适配器,并提供平台特定的实现示例。
### iOS 集成支持
详细的 iOS 集成指南,包括 SwiftUI 视图、手势处理和完整的 Demo 项目参考。
## 能力介绍
### 地图渲染
| **能力** | **说明** |
| --- | --- |
| 地图初始化 | SDK 初始化、设备激活、地图创建 |
| 栅格/矢量地图 | 标准栅格和卫星瓦片样式 |
| 视图控制 | 缩放、旋转、中心点调整 |
| 生命周期管理 | 初始化、激活、创建、渲染、销毁流程 |
### 覆盖物
| **能力** | **说明** |
| --- | --- |
| 点标注 | 地图上的点标注 |
| 线标注 | 路线和轨迹的线标注 |
| 面标注 | 区域标注 |
| 覆盖物管理 | 添加、移除、更新覆盖物 |
### 导航
| **能力** | **说明** |
| --- | --- |
| 轨迹导航 | 实时导航数据展示 |
| 导航回调 | 转向数据、距离、预计到达时间 |
| 转向图标 | 导航转向方向图标 |
### 平台适配器
| **能力** | **说明** |
| --- | --- |
| 内存适配器 | malloc/free/realloc 实现 |
| 文件适配器 | 文件 I/O 操作 |
| 网络适配器 | HTTP 请求处理 |
| 渲染适配器 | 地图渲染到屏幕(最关键) |
| 系统适配器 | 系统时间、设备信息 |
| 线程适配器 | 线程创建与同步 |
## 快速接入
### 第一步:在 Cursor 中配置 Skill
```bash
# 将 RTOS Skill 链接到您的项目
ln -s /path/to/open_sdk_skills/RTOS .cursor/skills/RTOS
```
### 第二步:验证配置
打开 Cursor AI Chat,输入:
```text
帮我初始化 WatchSDK 并创建一个地图视图,实现 iOS 平台所需的所有适配器
```
如果 AI 能够正确引用 RTOS Skill 文件并生成带有正确头文件类型检查的代码,说明 Skill 已成功加载。
### 第三步:关键集成步骤
1. **初始化 SDK** - 使用 `awk_init()` - 参见 [快速开始](api/quick-start.md)
2. **实现适配器** - 参见 [适配器指南](api/adapters.md)
3. **激活设备** - 使用 `awk_activate_device()` - 参见 [生命周期](api/lifecycle.md)
4. **创建地图** - 使用 `awk_map_create_view()` - 参见 [地图操作](api/map-operations.md)
## 使用示例
### 示例 1:SDK 初始化
```text
在 iOS 平台上初始化 WatchSDK,实现所有必需的适配器,包括内存、文件、网络、渲染、系统和线程适配器
```
### 示例 2:创建地图
```text
创建一个以北京为中心、缩放级别为 12 的地图视图,使用标准栅格瓦片样式
```
### 示例 3:添加覆盖物
```text
在地图上添加一条折线覆盖物,显示从 A 点到 B 点的导航路线
```
### 示例 4:导航集成
```text
初始化导航模块并设置回调,接收实时导航数据,包括转向方向和剩余距离
```
## 目录结构
```text
RTOS/
├── SKILL.md # 技能主文件(AI 入口)
├── api/ # API 使用指南
│ ├── quick-start.md # 快速完成 SDK 接入
│ ├── ios-integration.md # iOS 平台集成指南
│ ├── ios-demo-guide.md # iOS Demo 项目指南
│ ├── lifecycle.md # 初始化、激活、销毁流程
│ ├── adapters.md # 适配器实现指南
│ ├── map-operations.md # 地图创建与控制
│ ├── overlays.md # 覆盖物管理
│ └── navigation.md # 导航设置
└── references/ # 参考资料
├── adapter-requirements.md # 必须实现的适配器函数
├── core-types.md # 关键数据结构定义
├── error-codes.md # 错误码说明与排查
└── troubleshooting.md # FAQ 与问题排查
```
## 关键约束
1. **单线程模型**:所有 SDK 方法必须在同一主流程线程调用
2. **坐标系**:统一使用 GCJ02 坐标系
3. **激活要求**:首次使用需联网激活设备
4. **头文件优先**:编写集成代码前务必先读取 SDK 头文件
## 常见问题
### Q:地图显示空白/无渲染
**A:** 检查渲染适配器是否完整实现。三个关键函数是 `begin_drawing`、`commit_drawing` 和 `draw_bitmap`。空实现将导致地图无法显示。
### Q:枚举值编译错误
**A:** SDK 枚举命名不统一,务必读取头文件确认准确的枚举名称。例如,使用 `AWK_MAP_TILE_LOAD_ONLINE` 而非 `AWK_MAP_TILE_LOAD_MODE_ONLINE`。
### Q:结构体字段编译错误
**A:** 部分结构体字段命名特殊(如 `fill_ttyle` 而非 `fill_style`)。务必对照头文件定义验证字段名称。
## 相关链接
- [高德开放平台控制台](https://console.amap.com/)
- [Cursor 官方文档](https://docs.cursor.com/)
- [⬆️ 返回首页](../README_zh.md)
FILE:api/adapters.md
# 适配器实现
> SDK 通过适配器模式与平台解耦,需实现以下适配器
## 适配器概览
| 适配器 | 作用 | 必需 |
|--------|------|------|
| `memory_adapter` | 内存管理 | ✓ |
| `file_adapter` | 文件 I/O | ✓ |
| `system_adapter` | 系统服务 | ✓ |
| `network_adapter` | HTTP 请求 | ✓ |
| `render_adapter` | 地图绘制 | ✓ |
| `thread_adapter` | 线程管理 | ✓ |
---
## 内存适配器
```c
typedef struct {
void* (*mem_malloc)(size_t size);
void (*mem_free)(void* ptr);
void* (*mem_calloc)(size_t count, size_t size);
void* (*mem_realloc)(void* ptr, size_t size);
} awk_memory_adapter_t;
```
### POSIX 实现示例
```c
static void* awk_mem_malloc_adapter(size_t size) {
return malloc(size);
}
static void awk_mem_free_adapter(void* ptr) {
free(ptr);
}
static void* awk_mem_calloc_adapter(size_t count, size_t size) {
return calloc(count, size);
}
static void* awk_mem_realloc_adapter(void* ptr, size_t size) {
return realloc(ptr, size);
}
```
---
## 文件适配器
```c
typedef struct {
void* (*file_open)(const char *filename, const char *mode);
int (*file_close)(void* handler);
size_t (*file_read)(void *ptr, size_t size, void* handler);
size_t (*file_write)(void *ptr, size_t size, void* handler);
int (*file_seek)(void *handler, long offset, int where);
int (*file_flush)(void *handler);
bool (*file_exists)(const char *path);
bool (*file_dir_exists)(const char *path);
int (*file_mkdir)(const char *path, uint16_t mode);
int (*file_remove)(const char *path);
int (*file_rmdir)(const char *path);
void* (*file_opendir)(const char *path);
int (*file_closedir)(void *dir);
void (*file_readdir)(void *dir, awk_file_dir_foreach foreach, void *user_data);
size_t (*file_get_size)(const char *path);
long (*file_get_last_access)(const char *path);
int (*file_rename)(const char *old_name, const char *new_name);
int (*file_unzip)(const char *zip_path, const char *dest_path);
} awk_file_adapter_t;
```
### POSIX 实现示例
```c
static void* awk_file_open_adapter(const char *filename, const char *mode) {
return (void*)fopen(filename, mode);
}
static int awk_file_close_adapter(void* handler) {
return fclose((FILE*)handler);
}
static size_t awk_file_read_adapter(void *ptr, size_t size, void* handler) {
return fread(ptr, size, 1, (FILE*)handler);
}
static size_t awk_file_write_adapter(void *ptr, size_t size, void* handler) {
return fwrite(ptr, size, 1, (FILE*)handler);
}
static int awk_file_seek_adapter(void *handler, long offset, int where) {
return fseek((FILE*)handler, offset, where);
}
static bool awk_file_exists_adapter(const char *path) {
return access(path, 0) == 0;
}
static bool awk_file_dir_exists_adapter(const char *path) {
struct stat st;
return (stat(path, &st) == 0) && S_ISDIR(st.st_mode);
}
static int awk_file_mkdir_adapter(const char *path, uint16_t mode) {
return mkdir(path, mode);
}
static void awk_file_readdir_adapter(void *dir, awk_file_dir_foreach foreach, void *user_data) {
struct dirent *entry;
while ((entry = readdir((DIR*)dir)) != NULL) {
awk_file_dir_entry dir_entry = {.file_name = entry->d_name};
foreach(dir_entry, user_data);
}
}
```
---
## 系统适配器
```c
typedef struct {
uint64_t (*get_system_time)(void); // 返回毫秒级时间戳
void (*log_printf)(const char *format, ...);
} awk_system_adapter_t;
```
### 实现示例
```c
static uint64_t awk_get_system_time_adapter(void) {
struct timeval tv;
gettimeofday(&tv, NULL);
return (uint64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
static void awk_printf_adapter(const char *format, ...) {
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
```
---
## 网络适配器
```c
typedef struct {
void (*send)(awk_network_request_t *request, awk_network_callback callback);
void (*cancel)(int32_t request_id);
} awk_network_adapter_t;
```
**注意**:网络回调可在异步线程处理,但回调 SDK 时必须切回主线程。
---
## 渲染适配器
```c
typedef struct {
void (*begin_drawing)(uint32_t map_id, awk_render_context_t context);
void (*commit_drawing)(uint32_t map_id);
void (*draw_point)(uint32_t map_id, awk_point_t *point, uint32_t size, const awk_paint_style_t *style);
void (*draw_polyline)(uint32_t map_id, awk_point_t *points, uint32_t size, const awk_paint_style_t *style);
void (*draw_polygon)(uint32_t map_id, awk_point_t *points, uint32_t size, const awk_paint_style_t *style);
void (*draw_bitmap)(uint32_t map_id, awk_rect_area_t area, awk_bitmap_t bitmap, const awk_paint_style_t *style);
void (*draw_text)(uint32_t map_id, awk_point_t center, const char *text, const awk_paint_style_t *style);
void (*draw_color)(uint32_t map_id, awk_rect_area_t area, const awk_paint_style_t *style);
bool (*measure_text)(uint32_t map_id, const char *text, const awk_paint_style_t *style,
int32_t *width, int32_t *ascender, int32_t *descender);
} awk_render_adapter_t;
```
### 绘制流程
```
begin_drawing → draw_xxx (多次) → commit_drawing
```
### 绘制样式
```c
typedef struct {
uint32_t width; // 画笔宽度(像素)
uint32_t color; // ARGB 颜色
float angle; // 旋转角度 [0-360)
awk_text_style_t text_style; // 文字样式
awk_fill_style_t fill_style; // 填充样式
awk_dash_style_t dash_style; // 虚线样式
} awk_paint_style_t;
```
---
## 线程适配器
```c
typedef struct {
uint64_t (*get_thread_id)(void);
} awk_thread_adapter_t;
```
---
## 完整配置示例
```c
awk_context_t context = {0};
// 内存适配器
context.memory_adapter.mem_malloc = awk_mem_malloc_adapter;
context.memory_adapter.mem_free = awk_mem_free_adapter;
context.memory_adapter.mem_calloc = awk_mem_calloc_adapter;
context.memory_adapter.mem_realloc = awk_mem_realloc_adapter;
// 文件适配器
context.file_adapter.file_open = awk_file_open_adapter;
context.file_adapter.file_close = awk_file_close_adapter;
context.file_adapter.file_read = awk_file_read_adapter;
context.file_adapter.file_write = awk_file_write_adapter;
// ... 其他文件操作
// 系统适配器
context.system_adapter.get_system_time = awk_get_system_time_adapter;
context.system_adapter.log_printf = awk_printf_adapter;
// 网络适配器
context.network_adapter.send = awk_network_send_adapter;
context.network_adapter.cancel = awk_network_cancel_adapter;
// 渲染适配器
context.render_adapter.begin_drawing = awk_render_begin_drawing_adapter;
context.render_adapter.commit_drawing = awk_render_commit_drawing_adapter;
context.render_adapter.draw_bitmap = awk_render_bitmap_adapter;
// ... 其他渲染操作
// 线程适配器
context.thread_adapter.get_thread_id = awk_get_thread_id_adapter;
awk_init(&context);
```
## 下一步
- [地图操作](map-operations.md) - 创建和控制地图
- [核心类型](../references/core-types.md) - 了解数据结构定义
FILE:api/ios-demo-guide.md
# iOS Demo 功能实现指南
> 基于 WatchSDKDemo 工程的完整功能实现参考
## 概述
本文档基于 WatchSDKDemo 工程中的实际实现,详细说明如何使用 WatchSDK 实现常见的地图功能。
## 核心架构
### 架构图
```
AMapMainView (主界面)
↓ NavigationLink
AMapMyLocationView (我的地图)
↓
GDMapView (地图视图)
↓
GDMapViewModel (地图业务逻辑)
↓
GDWatchEngine (SDK 引擎封装)
↓
WatchSDK (C SDK)
```
### 关键类说明
| 类名 | 职责 |
|------|------|
| `GDWatchEngine` | SDK 引擎单例封装,提供所有 SDK 功能的统一入口 |
| `GDMapView` | SwiftUI 地图视图组件,处理手势和 UI 交互 |
| `GDMapViewModel` | 地图业务逻辑,管理地图状态和渲染回调 |
| `AMapMyLocationView` | 我的地图页面,整合地图和导航组件 |
| `AMapMyLocationViewModel` | 定位业务逻辑,管理当前位置 |
## "我的地图"功能实现
### 1. 主入口 - AMapMainView
用户点击"我的地图"按钮后,通过 `NavigationLink` 导航到地图页面:
```swift
NavigationLink {
GDDeferView {
AMapMyLocationView()
}
} label: {
HStack {
Image("ic-location-o")
.resizable()
.frame(width: GDSize.match(21), height: GDSize.match(21))
.foregroundColor(.blue)
Text("我的地图")
.font(Font.system(size: GDSize.match(18)))
}
.frame(height: GDSize.match(48))
}
.buttonStyle(.plain)
```
**关键点:**
- 使用 `GDDeferView` 延迟初始化,确保视图按需加载
- 按钮使用 `plain` 样式,保持界面简洁
### 2. 地图页面 - AMapMyLocationView
```swift
struct AMapMyLocationView: View {
var viewModel = AMapMyLocationViewModel()
var body: some View {
ZStack() {
// 地图视图
GDMapView(MapScene(mode: .location(mapCenter: viewModel.myLocation.coordinate),
tileStyle: GDTileStyleGridAndPoi))
.baseHandle { mapViewHandler in
viewModel.mapHandler = mapViewHandler
}
// UI 层
VStack(alignment: .leading) {
// 顶部返回按钮
HStack {
Image("ic-list-o 2")
.renderingMode(.template)
.foregroundColor(.white)
Spacer()
}
.decorateHandleBack {
viewModel.mapHandler?.destroy()
}
// 导航组件
AMapNaviView()
Spacer()
// 底部定位按钮
HStack {
Button {
viewModel.mapCenterMoveToMyLocation()
} label: {
Image("ic-location-o")
.renderingMode(.template)
.foregroundColor(.white)
.frame(width: GDSize.match(40), height: GDSize.match(40))
.background(Color(uiColor: UIColor.ltmColor(withHexString: "#222223")))
.cornerRadius(GDSize.match(12))
}
.buttonStyle(.plain)
Spacer()
}
}
}
.onDisappear {
viewModel.mapHandler?.destroy()
}
}
}
```
**关键点:**
- 使用 `ZStack` 叠加地图和 UI 层
- 通过 `baseHandle` 回调获取地图操作句柄
- 在 `onDisappear` 时销毁地图资源
### 3. 地图视图 - GDMapView
#### MapScene 配置
```swift
struct MapScene {
var mode: MapMode
var size = WKInterfaceDevice.current().screenBounds.size
var isUserInteractionEnabled = true
var zoom = 18.0
var eventDelegate: GDSceneEventProtocol? = nil
var tileStyle: GDTileStyle = GDTileStyleGridAndPoi
var sceneType: GDSceneType {
switch mode {
case .image(_):
return GDSceneTypePOI
case .location(_):
return GDSceneTypeMainMap
}
}
var pageType: GDPageType {
switch mode {
case .image(_):
return GDPageTypeDetail
case .location(_):
return GDPageTypeMainMap
}
}
func configMap(_ engine: GDWatchEngine, mapid: Int) {
engine.setViewport(size, mapId: mapid)
engine.setZoom(zoom, mapId: mapid)
switch mode {
case .image(let mapCenter), .location(let mapCenter):
if CLLocationCoordinate2DIsValid(mapCenter) {
engine.setMapCenterWithLocation(mapCenter, mapId: mapid)
}
}
}
}
```
#### 地图视图实现
```swift
struct GDMapView: View {
private var mapScene: MapScene
@ObservedObject private var mapData: GDMapViewModel
init(_ initScene: MapScene, handler: GDMapViewProtocol? = nil) {
mapScene = initScene
mapData = GDMapViewModel(mapScene)
}
var body: some View {
ZStack() {
if mapData.mapImage != nil {
Image(uiImage: mapData.mapImage!)
.resizable()
.gesture(drag)
.onTapGesture(count: 2) {
mapData.crownDidRotate(crownThresholdValue)
}
.onTapGesture { location in
mapData.onSingleTap(location)
}
} else {
ProgressView()
}
// 控制按钮
VStack(spacing: 5) {
Spacer()
// 缩放按钮
VStack(spacing: 0) {
Image(systemName: "plus")
.onTapGesture { mapData.zoomChange(1.0) }
Spacer().frame(height: 0.5)
Image(systemName: "minus")
.onTapGesture { mapData.zoomChange(-1.0) }
}
.cornerRadius(28)
Spacer()
}
}
.focusable(mapScene.isUserInteractionEnabled)
.digitalCrownRotation($crownValue, from: 0.1, through: 10.0, sensitivity: .low)
.onAppear { mapData.willActivate() }
.onDisappear { mapData.didDeactivate() }
}
var drag: some Gesture {
DragGesture(minimumDistance: 1, coordinateSpace: .local)
.onChanged { value in
if !isGesturing {
isGesturing = true
mapData.onPanBegin(value.startLocation)
}
mapData.onPanMoved(start: value.startLocation,
location: value.location,
velocity: CGPoint(x: 0, y: 0))
}
.onEnded { value in
isGesturing = false
mapData.onPanEnd(value.location)
}
}
}
```
**关键点:**
- 使用 `@ObservedObject` 监听地图状态变化
- 实现 `DragGesture` 处理地图拖拽
- 使用 `digitalCrownRotation` 支持表冠缩放
- 通过 `Image(uiImage:)` 显示 SDK 渲染的地图图片
### 4. 地图业务逻辑 - GDMapViewModel
```swift
class GDMapViewModel: NSObject, ObservableObject {
@Published var show = true
var scene: MapScene
var mapid = -1
@Published var mapImage: UIImage?
let engine = GDWatchEngine.sharedInstance()
init(_ inputScene: MapScene) {
engine.initEngine()
scene = inputScene
super.init()
let param = GDSceneParam()
param.sceneType = scene.sceneType
param.pageType = scene.pageType
param.size = WKInterfaceDevice.current().screenBounds.size
param.tileStyle = scene.tileStyle
mapid = Int(engine.createMapView(param, renderDelegate: self))
scene.configMap(engine, mapid: mapid)
engine.initNavi()
}
deinit {
print("GDMapViewModel deinit")
}
func willActivate() {
self.showMap()
}
func didDeactivate() {
self.hideMap()
}
// 手势处理
func onPanBegin(_ start: CGPoint) {
engine.onPanBegin(start, mapId: mapid)
}
func onPanMoved(start: CGPoint, location: CGPoint, velocity: CGPoint) {
engine.onPanMoved(location, velocity: velocity, mapId: mapid)
}
func onPanEnd(_ end: CGPoint) {
engine.onPanEnd(end, mapId: mapid)
}
func onSingleTap(_ point: CGPoint) {
engine.onSingleTap(point, mapId: mapid)
}
func crownDidRotate(_ rotationalDelta: Double) {
let zoom = engine.zoom(forMapId: mapid)
if rotationalDelta > 0 && zoom < 20 {
engine.setZoom(zoom + 1.0, mapId: mapid)
} else if rotationalDelta < 0 && zoom > 1 {
engine.setZoom(zoom - 1.0, mapId: mapid)
}
}
func zoomChange(_ value: Double) {
let zoom = engine.zoom(forMapId: mapid)
if value > 0 && zoom < 20 {
engine.setZoom(zoom + value, mapId: mapid)
}
if value < 0 && zoom > 0 {
engine.setZoom(zoom + value, mapId: mapid)
}
}
}
extension GDMapViewModel: AMapRenderDelegate {
func onRenderImage(_ image: UIImage) {
self.mapImage = image
}
func onShowMap(_ show: Bool) {
if show {
self.showMap()
} else {
self.hideMap()
}
}
func setNeedsRender() {
// 触发重新渲染
}
}
extension GDMapViewModel: GDMapBaseHandlerProtocol {
func setMapCenter(_ location: CLLocationCoordinate2D) {
engine.setMapCenterWithLocation(location, mapId: mapid)
}
func setZoom(_ value: Double) {
if value > 0 && value < 20 {
engine.setZoom(value, mapId: mapid)
}
}
func destroy() {
if mapid == -1 {
return
}
engine.destroyMapView(UInt32(mapid))
mapid = -1
}
func showMap() {
show = true
}
func hideMap() {
show = false
}
}
```
**关键点:**
- 实现 `AMapRenderDelegate` 接收 SDK 渲染回调
- 实现 `GDMapBaseHandlerProtocol` 提供地图操作接口
- 使用 `@Published` 属性驱动 SwiftUI 视图更新
- 在 `deinit` 时销毁地图资源
### 5. 定位逻辑 - AMapMyLocationViewModel
```swift
class AMapMyLocationViewModel: NSObject, ObservableObject {
var myLocation: CLLocation = CLLocation(latitude: 40.0039877, longitude: 116.488981)
private var hasShowRealLocation = false
var mapHandler: GDMapBaseHandlerProtocol?
override init() {
super.init()
// 获取真实定位
if let location = GDLocationManager.sharedInstance().engineLocation {
myLocation = location
hasShowRealLocation = true
} else {
GDLocationManager.sharedInstance().addObserver(self)
}
self.mapCenterMoveToMyLocation()
}
deinit {
GDLocationManager.sharedInstance().removeObserver(self)
}
func mapCenterMoveToMyLocation() {
mapHandler?.setMapCenter(myLocation.coordinate)
}
}
extension AMapMyLocationViewModel: GDLocationManagerDelegate {
func gdLocationManagerlocationDidUpdate(_ location: CLLocation) {
myLocation = location
if !hasShowRealLocation {
hasShowRealLocation = true
self.mapCenterMoveToMyLocation()
}
}
}
```
**关键点:**
- 优先使用真实定位,失败时使用默认坐标
- 实现定位回调,实时更新当前位置
- 首次获取到真实定位时自动移动地图中心
## GDWatchEngine 核心接口
### 初始化与生命周期
```objc
// 单例获取
+ (instancetype)sharedInstance;
// 初始化引擎
- (void)initEngine;
// 反初始化引擎
- (void)uninitEngine;
// 初始化导航
- (void)initNavi;
```
### 地图创建与销毁
```objc
// 创建地图视图
- (uint32_t)createMapView:(GDSceneParam *)sceneConfig
renderDelegate:(id<AMapRenderDelegate>)renderDelegate;
// 销毁地图视图
- (void)destroyMapView:(uint32_t)mapId;
// 恢复地图绘制
- (void)onRender_resume:(NSInteger)mapId;
// 暂停地图绘制
- (void)onRender_pause:(NSInteger)mapId;
```
### 地图控制
```objc
// 设置视口大小
- (void)setViewport:(CGSize)size mapId:(NSInteger)mapId;
// 获取缩放级别
- (CGFloat)zoomForMapId:(NSInteger)mapId;
// 设置缩放级别
- (void)setZoom:(CGFloat)zoom mapId:(NSInteger)mapId;
// 设置地图中心点
- (void)setMapCenterWithLocation:(CLLocationCoordinate2D)location
mapId:(NSInteger)mapId;
// 设置显示模式(锁车、全览、普通)
- (void)setShowMode:(awk_navi_show_mode_type)show_mode_type;
// 设置跟随模式(车头向上、北向上)
- (void)setTrackingMode:(awk_navi_tracking_mode_type)tracking_mode_type;
// 设置导航类型(驾车、骑行、步行)
- (void)set_navi_type:(awk_navi_type)navi_type;
```
### 手势处理
```objc
// 拖拽开始
- (void)onPanBegin:(CGPoint)startPoint mapId:(NSInteger)mapId;
// 拖拽移动
- (void)onPanMoved:(CGPoint)toPoint
velocity:(CGPoint)velocity
mapId:(NSInteger)mapId;
// 拖拽结束
- (void)onPanEnd:(CGPoint)endPoint mapId:(NSInteger)mapId;
// 单击
- (void)onSingleTap:(CGPoint)point mapId:(NSInteger)mapId;
```
### 覆盖物管理
```objc
// 添加基础覆盖物
- (void)addBaseOverlay:(NSInteger)mapId;
// 添加点覆盖物
- (void)addPointOverlay:(NSInteger)mapId;
// 添加线覆盖物
- (void)addLineOverlay:(NSInteger)mapId;
// 添加面覆盖物
- (void)addPolygonOverlay:(NSInteger)mapId;
// 添加轨迹导航覆盖物
- (void)addTrackNaviOverlay:(NSInteger)mapId;
```
### 离线地图
```objc
// 下载离线地图
- (void)downloadMap:(id<AMapDownloadDelegate>)downloadDelegate;
```
## AMapRenderDelegate 渲染回调
```objc
@protocol AMapRenderDelegate <NSObject>
// 渲染完成回调
- (void)onRenderImage:(UIImage *)image;
// 地图显示状态回调
- (void)onShowMap:(BOOL)show;
@end
```
## 导航组件 - AMapNaviView
导航组件展示实时导航信息,包括:
- 剩余距离
- 剩余时间
- 交通光柱
- 转向信息
- 速度信息
- 途经点
- 转向图标
导航数据通过 `GDNaviViewDelegate` 回调更新:
```objc
@protocol GDNaviViewDelegate <NSObject>
- (void)updateRemainDistance:(awk_navi_remain_distance_component)remain_distance;
- (void)updateRemainTime:(awk_navi_remain_time_component)remain_time;
- (void)updateTrafficBar:(awk_navi_traffic_bar_component)traffic_bar;
- (void)updateTurnInfoCard:(awk_navi_info_card_component)turn_info_card;
- (void)updateSpeedInfo:(awk_navi_speed_component)speed_info;
- (void)updateNorthUp:(awk_navi_north_up_component)north_up;
- (void)updateTrafficLightInfo:(awk_navi_traffic_signal_info_component)traffic_light;
- (void)updateRearVehicleInfo:(awk_navi_rear_vehicle_component)rear_vehicle;
- (void)updateLaneInfo:(awk_navi_lane_component)lane_info andImage:(UIImage *)image;
- (void)updateTrafficLightNum:(awk_navi_traffic_num_component)traffic_light_num;
@end
```
## 常见使用场景
### 场景 1:创建基础地图
```swift
// 创建地图场景
let scene = MapScene(
mode: .location(mapCenter: CLLocationCoordinate2D(latitude: 39.9, longitude: 116.4)),
tileStyle: GDTileStyleGridAndPoi
)
// 创建地图视图
let mapView = GDMapView(scene)
```
### 场景 2:移动地图中心
```swift
func setMapCenter(_ location: CLLocationCoordinate2D) {
mapHandler?.setMapCenter(location)
}
```
### 场景 3:缩放地图
```swift
// 放大
mapData.zoomChange(1.0)
// 缩小
mapData.zoomChange(-1.0)
// 设置指定缩放级别
mapData.setZoom(15.0)
```
### 场景 4:切换显示模式
```swift
// 锁车模式
engine.setShowMode(AWK_NAVI_SHOW_MODE_CAR_POSITION_LOCKED)
// 全览模式
engine.setShowMode(AWK_NAVI_SHOW_MODE_OVERVIEW)
```
### 场景 5:切换跟随模式
```swift
// 车头向上
engine.setTrackingMode(AWK_NAVI_TRACKING_MODE_CAR_NORTH)
// 北向上
engine.setTrackingMode(AWK_NAVI_TRACKING_MODE_MAP_NORTH)
```
### 场景 6:切换导航类型
```swift
// 驾车
engine.set_navi_type(AWK_NAVI_TYPE_DRIVE)
// 骑行
engine.set_navi_type(AWK_NAVI_TYPE_RIDE)
// 步行
engine.set_navi_type(AWK_NAVI_TYPE_WALK)
```
## 注意事项
### 1. 线程安全
- 所有 SDK 方法必须在**主线程**调用
- UI 更新必须在主线程执行
- 回调数据可能来自后台线程,需要切换到主线程处理
### 2. 资源管理
- 必须在 `onDisappear` 或 `deinit` 时调用 `destroyMapView`
- 避免重复创建或销毁地图
- 使用 `onRender_pause/onRender_resume` 控制渲染性能
### 3. 内存管理
- GDWatchEngine 使用单例模式,不需要手动释放
- GDMapViewModel 需要在视图销毁时释放
- 注意避免循环引用
### 4. 表冠旋转
- 表冠旋转值是连续的,需要处理边界情况
- 设置合理的缩放阈值,避免过度缩放
### 5. 手势冲突
- 拖拽手势可能与 SwiftUI 原生手势冲突
- 使用 `coordinateSpace: .local` 指定坐标系
- 设置合适的 `minimumDistance` 避免误触
## 相关文档
- [iOS 集成指南](ios-integration.md)
- [地图操作](map-operations.md)
- [导航](navigation.md)
- [适配器](adapters.md)
FILE:api/ios-integration.md
# iOS 平台接入指南
> 在 iOS 项目中集成 WatchSDK 的完整指南
## 概述
WatchSDK 是一个面向 RTOS 的 C 语言 SDK,在 iOS 中需要通过适配器模式桥接 iOS 的 Foundation 框架。
## 项目结构
```
YourProject/
├── libWatchSDK.a # 静态库
├── include/ # SDK 头文件
│ ├── awk.h
│ ├── awk_adapter.h
│ ├── awk_defines.h
│ ├── map/
│ │ ├── awk_map.h
│ │ └── awk_map_defines.h
│ └── navi/
│ ├── awk_navi.h
│ └── awk_navi_defines.h
└── RTOSPlayground/
├── WatchSDKManager.h # SDK 管理器
├── WatchSDKManager.m
├── WatchSDKAdapters.h # 适配器实现
└── WatchSDKAdapters.m
```
## 接入步骤
### 1. 添加静态库和头文件
**方法一:直接拖拽**
- 将 `libWatchSDK.a` 拖入 Xcode 项目
- 将 `include/` 文件夹拖入 Xcode 项目
- 勾选 `Copy items if needed`
- 确保 `Add to targets` 选中你的 App target
**方法二:配置 Build Settings**
1. 选择项目 target
2. `Build Settings` → `Library Search Paths`
- 添加: `$(PROJECT_DIR)/Vendor/WatchSDK`
3. `Build Settings` → `Header Search Paths`
- 添加: `$(PROJECT_DIR)/Vendor/WatchSDK/include`
### 2. 创建适配器
#### WatchSDKAdapters.h
```objc
#import <Foundation/Foundation.h>
#import "awk_adapter.h"
@interface WatchSDKAdapters : NSObject
+ (awk_memory_adapter_t)memoryAdapter;
+ (awk_file_adapter_t)fileAdapter;
+ (awk_system_adapter_t)systemAdapter;
+ (awk_network_adapter_t)networkAdapter;
+ (awk_render_adapter_t)renderAdapter;
+ (awk_thread_adapter_t)threadAdapter;
@end
```
#### WatchSDKAdapters.m
**内存适配器实现:**
```objc
+ (awk_memory_adapter_t)memoryAdapter {
static awk_memory_adapter_t adapter = {
.mem_malloc = aw_mem_malloc,
.mem_free = aw_mem_free,
.mem_calloc = aw_mem_calloc,
.mem_realloc = aw_mem_realloc
};
return adapter;
}
static void* aw_mem_malloc(size_t size) {
return malloc(size);
}
static void aw_mem_free(void* ptr) {
if (ptr) free(ptr);
}
static void* aw_mem_calloc(size_t count, size_t size) {
return calloc(count, size);
}
static void* aw_mem_realloc(void* ptr, size_t size) {
return realloc(ptr, size);
}
```
**系统适配器实现:**
```objc
+ (awk_system_adapter_t)systemAdapter {
static awk_system_adapter_t adapter = {
.get_system_time = aw_get_system_time,
.log_printf = aw_log_printf
};
return adapter;
}
static uint64_t aw_get_system_time(void) {
struct timeval tv;
gettimeofday(&tv, NULL);
return (uint64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
static int aw_log_printf(const char *format, ...) {
va_list args;
va_start(args, format);
NSString *message = [[NSString alloc] initWithFormat:[NSString stringWithUTF8String:format]
arguments:args];
va_end(args);
NSLog(@"[WatchSDK] %@", message);
return 0;
}
```
**线程适配器实现:**
```objc
+ (awk_thread_adapter_t)threadAdapter {
static awk_thread_adapter_t adapter = {
.get_thread_id = aw_get_thread_id
};
return adapter;
}
static uint64_t aw_get_thread_id(void) {
pthread_t pid = pthread_self();
return (uint64_t)pid;
}
```
### 3. 创建 SDK 管理器
#### WatchSDKManager.h
```objc
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
typedef void (^WatchSDKActivateSuccessCallback)(void);
typedef void (^WatchSDKActivateFailCallback)(int32_t errorCode, NSString *errorMessage);
@interface WatchSDKManager : NSObject
+ (instancetype)sharedManager;
/**
* 初始化 SDK
* @param deviceId 设备 ID
* @param amapKey 高德开放平台 key
* @param rootDir SDK 数据根目录
* @return 0=成功,负数=错误码
*/
- (int32_t)initializeWithDeviceId:(NSString *)deviceId
amapKey:(NSString *)amapKey
rootDir:(NSString *)rootDir;
/**
* 激活设备(首次使用需联网激活)
*/
- (void)activateDeviceWithSuccess:(WatchSDKActivateSuccessCallback)successCallback
failure:(WatchSDKActivateFailCallback)failCallback;
/**
* 创建地图视图
*/
- (int32_t)createMapViewWithWidth:(int32_t)width height:(int32_t)height;
/**
* 销毁地图视图
*/
- (void)destroyMapView:(int32_t)mapId;
/**
* 执行地图渲染(需要在主循环中定时调用)
*/
- (void)doRender;
/**
* 反初始化 SDK
*/
- (void)uninitialize;
@end
NS_ASSUME_NONNULL_END
```
#### WatchSDKManager.m
```objc
#import "WatchSDKManager.h"
#import "WatchSDKAdapters.h"
#import "awk.h"
// 全局回调存储
static WatchSDKActivateSuccessCallback g_successCallback = nil;
static WatchSDKActivateFailCallback g_failCallback = nil;
static void on_activate_success(const char* license_id) {
if (g_successCallback) {
dispatch_async(dispatch_get_main_queue(), ^{
g_successCallback();
g_successCallback = nil;
g_failCallback = nil;
});
}
}
static void on_activate_fail(int32_t error_code, const char* error_message) {
if (g_failCallback) {
NSString *msg = error_message ? [NSString stringWithUTF8String:error_message] : @"Unknown error";
dispatch_async(dispatch_get_main_queue(), ^{
g_failCallback(error_code, msg);
g_successCallback = nil;
g_failCallback = nil;
});
}
}
@implementation WatchSDKManager
+ (instancetype)sharedManager {
static WatchSDKManager *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[WatchSDKManager alloc] init];
});
return instance;
}
- (int32_t)initializeWithDeviceId:(NSString *)deviceId
amapKey:(NSString *)amapKey
rootDir:(NSString *)rootDir {
if (!deviceId || !amapKey || !rootDir) {
return -2;
}
// 创建根目录
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:rootDir]) {
NSError *error = nil;
[fileManager createDirectoryAtPath:rootDir
withIntermediateDirectories:YES
attributes:nil
error:&error];
if (error) {
return -3;
}
}
// 构建初始化上下文
awk_context_t context;
memset(&context, 0, sizeof(awk_context_t));
context.device_id = [deviceId UTF8String];
context.key = [amapKey UTF8String];
context.root_dir = [rootDir UTF8String];
context.tile_mem_cache_max_size = 6; // KB
context.tile_disk_cache_max_size = 200; // MB
// 设置适配器
context.memory_adapter = [WatchSDKAdapters memoryAdapter];
context.file_adapter = [WatchSDKAdapters fileAdapter];
context.system_adapter = [WatchSDKAdapters systemAdapter];
context.network_adapter = [WatchSDKAdapters networkAdapter];
context.render_adapter = [WatchSDKAdapters renderAdapter];
context.thread_adapter.get_thread_id = aw_get_thread_id;
// 调用 SDK 初始化
int32_t result = awk_init(&context);
return result;
}
- (void)activateDeviceWithSuccess:(WatchSDKActivateSuccessCallback)successCallback
failure:(WatchSDKActivateFailCallback)failCallback {
g_successCallback = [successCallback copy];
g_failCallback = [failCallback copy];
awk_device_activate_param_t param = {
.area = "mainland",
.country = "cn",
.type = 0,
.data_type = "raster"
};
awk_device_active_callback callback = {
.awk_device_active_on_success = on_activate_success,
.awk_device_active_on_fail = on_activate_fail
};
awk_activate_device(¶m, callback);
}
- (int32_t)createMapViewWithWidth:(int32_t)width height:(int32_t)height {
awk_map_view_param_t param = {
.port = {width, height}
};
return awk_map_create_view(param);
}
- (void)destroyMapView:(int32_t)mapId {
awk_map_destroy_view(mapId);
}
- (void)doRender {
awk_map_do_render();
}
- (void)uninitialize {
awk_uninit();
}
@end
```
### 4. 在 ViewController 中使用
```objc
#import "MapViewController.h"
#import "WatchSDKManager.h"
@interface MapViewController ()
@property (nonatomic, strong) CADisplayLink *renderTimer;
@property (nonatomic, assign) int32_t mapId;
@end
@implementation MapViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 1. 初始化 SDK
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *rootDir = [paths.firstObject stringByAppendingPathComponent:@"WatchSDKData"];
NSString *deviceId = [[UIDevice currentDevice] identifierForVendor].UUIDString;
NSString *amapKey = @"your_amap_key";
WatchSDKManager *manager = [WatchSDKManager sharedManager];
int32_t result = [manager initializeWithDeviceId:deviceId amapKey:amapKey rootDir:rootDir];
if (result == 0) {
NSLog(@"SDK 初始化成功");
[self activateDevice];
}
}
- (void)activateDevice {
[[WatchSDKManager sharedManager] activateDeviceWithSuccess:^{
NSLog(@"设备激活成功");
[self createMap];
} failure:^(int32_t errorCode, NSString *errorMessage) {
NSLog(@"激活失败: %@", errorMessage);
}];
}
- (void)createMap {
CGSize screenSize = [UIScreen mainScreen].bounds.size;
CGFloat scale = [UIScreen mainScreen].scale;
self.mapId = [[WatchSDKManager sharedManager] createMapViewWithWidth:(int32_t)(screenSize.width * scale)
height:(int32_t)(screenSize.height * scale)];
if (self.mapId > 0) {
[self startRenderTimer];
}
}
- (void)startRenderTimer {
self.renderTimer = [CADisplayLink displayLinkWithTarget:self
selector:@selector(render)];
[self.renderTimer addToRunLoop:[NSRunLoop mainRunLoop]
forMode:NSRunLoopCommonModes];
}
- (void)render {
[[WatchSDKManager sharedManager] doRender];
}
- (void)dealloc {
if (self.renderTimer) {
[self.renderTimer invalidate];
}
if (self.mapId > 0) {
[[WatchSDKManager sharedManager] destroyMapView:self.mapId];
}
}
@end
```
## 关键注意事项
### 1. 线程模型
⚠️ SDK 为单线程模型,所有 SDK 方法必须在主线程调用:
```objc
// ✅ 正确:在主线程调用
dispatch_async(dispatch_get_main_queue(), ^{
awk_map_do_render();
});
// ❌ 错误:在后台线程调用
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
awk_map_do_render(); // 可能导致异常
});
```
### 2. 回调处理
SDK 的回调函数需要在主线程执行,使用 GCD 切换:
```objc
static void on_activate_success(const char* license_id) {
dispatch_async(dispatch_get_main_queue(), ^{
// 处理成功回调
});
}
```
### 3. 渲染循环
使用 CADisplayLink 在主线程定时调用渲染:
```objc
self.renderTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(render)];
[self.renderTimer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
```
### 4. 内存管理
适配器的内存操作直接使用系统函数:
```objc
static void* aw_mem_malloc(size_t size) {
return malloc(size);
}
static void aw_mem_free(void* ptr) {
if (ptr) free(ptr);
}
```
## 常见问题
### Q: 编译错误 "Undefined symbols for architecture arm64"
**原因**:静态库未正确链接
**解决**:
1. 检查 `Library Search Paths` 是否正确
2. 确认静态库架构与项目架构一致
3. 使用 `lipo -info libWatchSDK.a` 查看静态库支持的架构
### Q: 头文件找不到
**原因**:`Header Search Paths` 配置错误
**解决**:
```
Build Settings → Header Search Paths
添加: $(PROJECT_DIR)/Vendor/WatchSDK/include
勾选: Recursive
```
### Q: 地图不显示
**排查步骤**:
1. 确认设备已激活
2. 检查渲染定时器是否启动
3. 确认 `render_adapter` 实现正确
4. 检查地图尺寸是否有效
## 下一步
- [适配器实现](adapters.md) - 查看完整适配器实现
- [快速开始](quick-start.md) - 了解基础接入流程
- [地图操作](map-operations.md) - 学习地图控制 API
FILE:api/lifecycle.md
# 生命周期管理
> SDK 初始化、激活、销毁的完整流程
## 生命周期流程
```
┌─────────────┐
│ awk_init │ ← 环境初始化
└──────┬──────┘
▼
┌─────────────────────┐
│ awk_activate_device │ ← 设备激活(首次)
└──────┬──────────────┘
▼
┌─────────────────────┐
│ awk_map_create_view │ ← 创建地图
└──────┬──────────────┘
▼
┌─────────────────────┐
│ awk_map_do_render │ ← 渲染循环
└──────┬──────────────┘
▼
┌──────────────────────┐
│ awk_map_destroy_view │ ← 销毁地图
└──────┬───────────────┘
▼
┌─────────────┐
│ awk_uninit │ ← 反初始化
└─────────────┘
```
## 初始化
### awk_init
```c
int32_t awk_init(awk_context_t *context);
```
**参数 `awk_context_t`:**
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `device_id` | char* | ✓ | 设备唯一标识 |
| `key` | char* | ✓ | 高德开放平台智能硬件 key |
| `root_dir` | char* | ✓ | SDK 内部文件夹根路径 |
| `tile_mem_cache_max_size` | uint32_t | | 瓦片内存缓存,单位:KB |
| `tile_disk_cache_max_size` | uint32_t | | 瓦片磁盘缓存,单位:MB |
| `tile_load_mode` | int32_t | | 加载模式:离线/在线/混合 |
| `tile_pixel_mode` | awk_pixel_mode_t | | 像素格式 |
| `memory_adapter` | awk_memory_adapter_t | ✓ | 内存适配器 |
| `file_adapter` | awk_file_adapter_t | ✓ | 文件适配器 |
| `network_adapter` | awk_network_adapter_t | ✓ | 网络适配器 |
| `render_adapter` | awk_render_adapter_t | ✓ | 渲染适配器 |
| `system_adapter` | awk_system_adapter_t | ✓ | 系统适配器 |
**返回值:**
| 值 | 说明 |
|----|------|
| 0 | 成功 |
| -1 | 已初始化,不能重复初始化 |
| -100 | context 为空 |
| -101 | key 为空 |
| -102 | device_id 为空 |
| -103 | root_dir 为空 |
| -2xx | render_adapter 函数指针为空 |
| -3xx | file_adapter 函数指针为空 |
| -4xx | memory_adapter 函数指针为空 |
| -5xx | system_adapter 函数指针为空 |
| -6xx | network_adapter 函数指针为空 |
### awk_uninit
```c
int32_t awk_uninit(void);
```
**返回值:**
| 值 | 说明 |
|----|------|
| 0 | 成功 |
| -1 | 未初始化 |
| -3 | 调用线程与初始化线程不一致 |
## 设备激活
### awk_activate_device
首次使用需联网激活,未激活 SDK 不可用。
```c
void awk_activate_device(
awk_device_activate_param_t *param,
awk_device_active_callback callback
);
```
**参数 `awk_device_activate_param_t`:**
| 字段 | 说明 |
|------|------|
| `area` | 区域:`mainland`=国内,`overseas`=海外 |
| `country` | 地图主张:`cn` |
| `type` | 0=新激活,1=恢复出厂,2=续约 |
| `data_type` | `raster`=栅格,`vector`=矢量 |
**回调:**
```c
typedef struct {
void (*awk_device_active_on_success)(const char* license_id);
void (*awk_device_active_on_fail)(int code, const char* msg);
} awk_device_active_callback;
```
**错误码:**
| 码 | 说明 |
|----|------|
| 30046 | license 数量超限 |
| 30047 | license 已存在 |
| 30048 | license 已禁用 |
| 30049 | license 超过有效期 |
### awk_check_device_activated
检查设备是否已激活:
```c
bool awk_check_device_activated(
awk_device_activate_param_t *param,
awk_context_t *context
);
```
## 缓存管理
### 清除磁盘缓存
```c
int32_t awk_clear_disk_cache(void);
```
### 清除内存缓存
```c
int32_t awk_clear_memory_cache(awk_memory_cache_type_t type);
```
**缓存类型:**
| 值 | 说明 |
|----|------|
| `AWK_MEMORY_CACHE_TYPE_TILE` | 瓦片缓存 |
| `AWK_MEMORY_CACHE_TYPE_POI` | POI 缓存 |
## 线程模型
⚠️ **重要约束**:
1. SDK 为**单线程模型**
2. 所有方法必须在**同一主流程线程**调用
3. 网络回调可在异步线程处理,但回调 SDK 时必须切回主线程
4. 并发调用可能导致异常
## 下一步
- [适配器实现](adapters.md) - 实现平台适配器
- [地图操作](map-operations.md) - 创建和控制地图
FILE:api/map-operations.md
# 地图操作
> 创建、控制、渲染地图
## 创建与销毁
### 创建地图
```c
int32_t awk_map_create_view(awk_map_view_param_t param);
```
**参数:**
```c
typedef struct {
awk_map_view_port_t port; // 视口大小
} awk_map_view_param_t;
typedef struct {
int32_t width; // 宽度(像素)
int32_t height; // 高度(像素)
} awk_map_view_port_t;
```
**返回值:**
| 值 | 说明 |
|----|------|
| >0 | 地图实例 ID |
| -1 | 未初始化 |
| -2 | license 校验失败 |
| -3 | 线程不一致 |
**示例:**
```c
awk_map_view_param_t param;
param.port.width = 375;
param.port.height = 667;
int32_t map_id = awk_map_create_view(param);
if (map_id > 0) {
// 创建成功
}
```
### 销毁地图
```c
int32_t awk_map_destroy_view(uint32_t map_id);
```
---
## 渲染控制
### 执行渲染
```c
int32_t awk_map_do_render(void);
```
需在主循环中定时调用。
### 暂停/恢复渲染
```c
int32_t awk_map_pause_render(uint32_t map_id);
int32_t awk_map_resume_render(uint32_t map_id);
```
---
## 地图状态控制
### 设置中心点
```c
int32_t awk_map_set_center(uint32_t map_id, awk_map_coord2d_t center);
```
```c
awk_map_coord2d_t center = {
.lon = 116.397428, // 经度
.lat = 39.90923 // 纬度
};
awk_map_set_center(map_id, center);
```
### 设置缩放级别
```c
int32_t awk_map_set_level(uint32_t map_id, float level);
```
- 范围:3-20
- 可通过 `limit_min_zoom` / `limit_max_zoom` 限制
### 设置旋转角度
```c
int32_t awk_map_set_roll_angle(uint32_t map_id, float angle);
```
- 范围:0-360
- 0 度为正北
### 获取地图状态
```c
int32_t awk_map_get_posture(uint32_t map_id, awk_map_posture_t *posture);
```
```c
typedef struct {
awk_map_coord2d_t center; // 中心点
float level; // 缩放级别
float roll_angle; // 旋转角度
} awk_map_posture_t;
```
---
## 手势操作
```c
// 手势开始
int32_t awk_map_touch_begin(uint32_t map_id, int32_t x, int32_t y);
// 手势移动
int32_t awk_map_touch_update(uint32_t map_id, int32_t x, int32_t y);
// 手势结束
int32_t awk_map_touch_end(uint32_t map_id, int32_t x, int32_t y);
```
---
## 坐标转换
### 经纬度 → 屏幕坐标
```c
int32_t awk_map_lonlat_to_xy(uint32_t map_id, awk_map_coord2d_t lonlat, int32_t *x, int32_t *y);
```
### 屏幕坐标 → 经纬度
```c
int32_t awk_map_xy_to_lonlat(uint32_t map_id, int32_t x, int32_t y, awk_map_coord2d_t *lonlat);
```
### 计算两点距离
```c
double awk_map_calc_points_distance(double lon1, double lat1, double lon2, double lat2);
```
返回距离,单位:米。
---
## 渲染回调
```c
typedef struct {
// 覆盖物绘制回调
bool (*on_point_begin_draw)(uint32_t map_id, int32_t guid);
void (*on_point_end_draw)(uint32_t map_id, int32_t guid, int32_t status);
bool (*on_line_begin_draw)(uint32_t map_id, int32_t guid);
void (*on_line_end_draw)(uint32_t map_id, int32_t guid, int32_t status);
bool (*on_polygon_begin_draw)(uint32_t map_id, int32_t guid);
void (*on_polygon_end_draw)(uint32_t map_id, int32_t guid, int32_t status);
// 瓦片绘制回调
bool (*on_tile_begin_draw)(uint32_t map_id, uint32_t tile_x, uint32_t tile_y, uint32_t zoom);
void (*on_tile_end_draw)(uint32_t map_id, uint32_t tile_x, uint32_t tile_y, uint32_t zoom, int32_t status);
// 瓦片下载回调
bool (*on_tile_begin_download)(int32_t type, uint32_t tile_x, uint32_t tile_y, uint32_t zoom);
void (*on_tile_end_download)(int32_t type, uint32_t tile_x, uint32_t tile_y, uint32_t zoom, awk_map_tile_response_status_t status);
} awk_map_render_callback_t;
```
## 下一步
- [覆盖物](overlays.md) - 添加点/线/面标注
- [导航](navigation.md) - 导航功能接入
FILE:api/navigation.md
# 导航功能
> 实时导航数据展示与控制
## 导航流程
```
awk_init_navi → awk_init_navi_view → awk_navi_data → 回调处理 → awk_uninit_navi
```
---
## 初始化
### 初始化导航
```c
int32_t awk_init_navi(awk_navi_config_t *config);
```
**配置参数:**
```c
typedef struct {
awk_map_point_overlay_t car_overlay; // 车标覆盖物
// ... 其他配置
} awk_navi_config_t;
```
### 初始化导航视图
```c
int32_t awk_init_navi_view(uint32_t map_id, awk_navi_view_config_t *view_config);
```
⚠️ **注意**:导航中外部不可操作地图(旋转、缩放等),否则会与内部操作冲突。
### 反初始化
```c
int32_t awk_uninit_navi(void);
int32_t awk_uninit_navi_view(void);
```
---
## 数据回调
### 设置回调
```c
int32_t awk_navi_add_data_callback(awk_navi_data_callback_t *callback);
int32_t awk_navi_remove_data_callback(awk_navi_data_callback_t *callback);
```
### 回调结构
```c
typedef struct {
// 路线更新
void (*update_navi_route_group)(awk_navi_data_callback_t *cb,
awk_navi_route_group_t route_group,
awk_navi_data_info_t data_info);
// 导航信息更新
void (*update_navi_info)(awk_navi_data_callback_t *cb,
awk_navi_info_t navi_info,
awk_navi_data_info_t data_info);
// 自车位置更新
void (*update_navi_location)(awk_navi_data_callback_t *cb,
awk_navi_location_t location,
awk_navi_data_info_t data_info);
// 转向图标更新
void (*update_turn_info)(awk_navi_data_callback_t *cb,
awk_navi_icon_type turn_icon_type,
awk_navi_data_info_t data_info);
// 下一路口转向
void (*update_next_turn_info)(awk_navi_data_callback_t *cb,
awk_navi_icon_type turn_icon_type,
awk_navi_data_info_t data_info);
// 后方来车提醒
void (*show_rear_appr_vehicle)(awk_navi_data_callback_t *cb,
awk_navi_rear_vehicle_info_t info,
awk_navi_data_info_t data_info);
void (*hide_rear_appr_vehicle)(awk_navi_data_callback_t *cb,
awk_navi_data_info_t data_info);
// 红绿灯倒计时
void (*show_traffic_signal)(awk_navi_data_callback_t *cb,
awk_navi_traffic_signal_info_t info,
awk_navi_data_info_t data_info);
void (*hide_traffic_signal)(awk_navi_data_callback_t *cb,
awk_navi_data_info_t data_info);
// 车道线信息
void (*show_lane_info)(awk_navi_data_callback_t *cb,
awk_navi_lane_info_t lane_info,
awk_navi_data_info_t data_info);
void (*hide_lane_info)(awk_navi_data_callback_t *cb,
awk_navi_data_info_t data_info);
} awk_navi_data_callback_t;
```
---
## 事件回调
```c
int32_t awk_navi_add_event_callback(awk_navi_event_callback_t *callback);
int32_t awk_navi_remove_event_callback(awk_navi_event_callback_t *callback);
```
```c
typedef struct {
void (*on_arrived_destination)(awk_navi_event_callback_t *cb);
void (*on_reset)(awk_navi_event_callback_t *cb);
} awk_navi_event_callback_t;
```
---
## 导航数据输入
```c
int32_t awk_navi_data(const uint8_t *data, size_t len);
```
传入导航 PB 数据,内部解析。
**返回值:**
| 值 | 说明 |
|----|------|
| 0 | 成功 |
| -10000 | 数据结构异常 |
| -10001 | 反初始化后调用 |
| -2, -7, -20 | 需重传数据 |
---
## 显示控制
### 跟随模式
```c
int32_t awk_navi_set_tracking_mode(awk_navi_tracking_mode_type mode);
```
| 模式 | 说明 |
|------|------|
| 北朝上 | 地图始终北朝上 |
| 车头朝上 | 地图随车头方向旋转 |
### 显示模式
```c
int32_t awk_navi_set_show_mode(awk_navi_show_mode_type mode);
```
| 模式 | 说明 |
|------|------|
| 锁车状态 | 跟随车辆 |
| 全览状态 | 显示完整路线 |
| 普通状态 | 自由浏览 |
### UI 元素显示
```c
int32_t awk_navi_show_ui_elements(bool show);
```
控制除底图和路线外的所有 UI 元素。
---
## 车标控制
### 自动旋转
```c
int32_t awk_navi_should_autorotate_car(bool should_autorotate);
```
### 手动设置角度
```c
int32_t awk_navi_set_car_angle(float angle);
```
- 需先设置 `awk_navi_should_autorotate_car(false)`
- 角度:0=北,90=东,180=南,270=西
---
## 状态查询
### 是否导航中
```c
bool awk_navi_is_navigating(void);
```
### 获取地图 ID
```c
int32_t awk_navi_get_map_id(void);
```
---
## 完整示例
```c
// 1. 初始化导航
awk_navi_config_t config = {0};
awk_init_navi(&config);
// 2. 设置回调
awk_navi_data_callback_t data_cb = {
.update_navi_info = on_navi_info_update,
.update_navi_location = on_location_update,
.update_turn_info = on_turn_info_update
};
awk_navi_add_data_callback(&data_cb);
// 3. 初始化导航视图
awk_navi_view_config_t view_config = {0};
awk_init_navi_view(map_id, &view_config);
// 4. 接收导航数据
awk_navi_data(pb_data, pb_len);
// 5. 清理
awk_uninit_navi_view();
awk_uninit_navi();
```
## 下一步
- [核心类型](../references/core-types.md) - 导航相关数据结构
- [错误码](../references/error-codes.md) - 错误处理
FILE:api/overlays.md
# 覆盖物
> 点/线/面覆盖物的创建与管理
## 覆盖物类型
| 类型 | 结构体 | 用途 |
|------|--------|------|
| 点 | `awk_map_point_overlay_t` | 标记位置、POI |
| 线 | `awk_map_polyline_overlay_t` | 路径、轨迹 |
| 面 | `awk_map_polygon_overlay_t` | 区域、范围 |
---
## 点覆盖物
### 创建
```c
// 1. 初始化
awk_map_point_overlay_t point;
awk_map_init_point_overlay(&point);
// 2. 设置位置
point.position.lon = 116.397428;
point.position.lat = 39.90923;
// 3. 设置图标(可选)
point.normal_marker.icon_texture.texture_id = texture_id;
point.normal_marker.icon_texture.scale = 0.8f;
// 4. 添加到地图
awk_map_add_overlay(map_id, (awk_map_base_overlay_t *)&point);
```
### 纹理管理
```c
// 添加纹理
awk_map_texture_data_t texture = {
.pixel_mode = AWK_PIXEL_MODE_ARGB_8888,
.buffer = image_data,
.buffer_size = data_size,
.width = 32,
.height = 32
};
int32_t texture_id = awk_map_add_texture(&texture);
// 更新纹理
awk_map_update_texture(texture_id, &new_texture);
// 移除纹理
awk_map_remove_texture(texture_id);
```
---
## 线覆盖物
### 创建
```c
// 1. 初始化
awk_map_polyline_overlay_t line;
awk_map_init_line_overlay(&line);
// 2. 设置坐标点
line.point_size = 3;
line.points = malloc(sizeof(awk_map_coord2d_t) * 3);
line.points[0] = (awk_map_coord2d_t){116.397428, 39.90923};
line.points[1] = (awk_map_coord2d_t){116.407428, 39.91923};
line.points[2] = (awk_map_coord2d_t){116.417428, 39.92923};
// 3. 设置样式
line.normal_marker.line_width = 4; // 线宽(像素)
line.normal_marker.line_color = 0xFFFF0000; // ARGB: 红色
line.normal_marker.border_width = 2; // 边框宽度
line.normal_marker.border_color = 0xFFFFFFFF; // ARGB: 白色
// 4. 添加到地图
awk_map_bindadd_overlay(map_id, (awk_map_base_overlay_t *)&line);
// 5. 释放内存
free(line.points);
```
### 虚线样式
```c
line.normal_marker.dash_style.painted_length = 10; // 绘制长度
line.normal_marker.dash_style.unpainted_length = 5; // 空白长度
line.normal_marker.dash_style.offset = 0; // 起始偏移
```
---
## 面覆盖物
### 创建
```c
// 1. 初始化
awk_map_polygon_overlay_t polygon;
awk_map_init_polygon_overlay(&polygon);
// 2. 设置坐标点(至少3个点)
polygon.point_size = 4;
polygon.points = malloc(sizeof(awk_map_coord2d_t) * 4);
polygon.points[0] = (awk_map_coord2d_t){116.397428, 39.90923};
polygon.points[1] = (awk_map_coord2d_t){116.407428, 39.90923};
polygon.points[2] = (awk_map_coord2d_t){116.407428, 39.91923};
polygon.points[3] = (awk_map_coord2d_t){116.397428, 39.91923};
// 3. 设置填充颜色
polygon.color = 0x80FF0000; // ARGB: 半透明红色
// 4. 添加到地图
awk_map_bindadd_overlay(map_id, (awk_map_base_overlay_t *)&polygon);
// 5. 释放内存
free(polygon.points);
```
---
## 覆盖物管理
### 添加
```c
int32_t awk_map_add_overlay(uint32_t map_id, awk_map_base_overlay_t *overlay);
```
**返回值:**
| 值 | 说明 |
|----|------|
| 0 | 成功 |
| -1 | 未初始化 |
| -2 | guid 已存在 |
| -3 | overlay 为空或类型错误 |
| -4 | 线程不一致 |
### 移除
```c
int32_t awk_map_remove_overlay(uint32_t map_id, int32_t overlay_id);
```
### 查找
```c
const awk_map_base_overlay_t* awk_map_find_overlay(uint32_t map_id, int32_t overlay_id);
```
### 获取数量
```c
uint32_t awk_map_get_overlay_count(uint32_t map_id);
```
### 按索引获取
```c
const awk_map_base_overlay_t* awk_map_get_overlay(uint32_t map_id, uint32_t index);
```
---
## 颜色格式
所有颜色使用 **ARGB** 格式(32位):
```
0xAARRGGBB
│ │ │ └─ 蓝色 (0-255)
│ │ └─── 绿色 (0-255)
│ └───── 红色 (0-255)
└─────── 透明度 (0=透明, 255=不透明)
```
**示例:**
| 颜色 | 值 |
|------|-----|
| 不透明红色 | `0xFFFF0000` |
| 半透明蓝色 | `0x800000FF` |
| 不透明白色 | `0xFFFFFFFF` |
| 不透明黑色 | `0xFF000000` |
## 下一步
- [导航](navigation.md) - 导航功能接入
- [核心类型](../references/core-types.md) - 数据结构定义
FILE:api/quick-start.md
# 快速开始
> 5 分钟完成 WatchSDK 接入
## 最简接入流程
```
初始化 SDK → 激活设备 → 创建地图 → 渲染循环
```
## 1. 初始化 SDK
```c
#include "awk.h"
awk_context_t context;
memset(&context, 0, sizeof(awk_context_t));
// 必填参数
context.device_id = "your_device_id";
context.key = "your_amap_key"; // 高德开放平台智能硬件 key
context.root_dir = "/path/to/sdk/data"; // SDK 内部文件夹根路径
// 缓存配置
context.tile_mem_cache_max_size = 6; // 内存缓存,单位:KB
context.tile_disk_cache_max_size = 200; // 磁盘缓存,单位:MB
// 设置适配器(必需)
context.memory_adapter = your_memory_adapter;
context.file_adapter = your_file_adapter;
context.system_adapter = your_system_adapter;
context.network_adapter = your_network_adapter;
context.render_adapter = your_render_adapter;
context.thread_adapter = your_thread_adapter;
int32_t result = awk_init(&context);
// result: 0=成功, 负数=错误码
```
**→ 适配器实现详见 [适配器文档](adapters.md)**
## 2. 激活设备
首次使用需联网激活:
```c
awk_device_activate_param_t param = {
.area = "mainland", // mainland=国内, overseas=海外
.country = "cn",
.type = 0, // 0=新激活, 1=恢复出厂, 2=续约
.data_type = "raster" // raster=栅格, vector=矢量
};
awk_device_active_callback callback = {
.awk_device_active_on_success = on_activate_success,
.awk_device_active_on_fail = on_activate_fail
};
awk_activate_device(¶m, callback);
```
## 3. 创建地图
```c
awk_map_view_param_t param;
param.port.width = 375; // 地图宽度(像素)
param.port.height = 667; // 地图高度(像素)
int32_t map_id = awk_map_create_view(param);
// map_id > 0 表示成功
```
## 4. 渲染循环
```c
// 在主循环中定时调用
while (running) {
awk_map_do_render();
// ... 其他逻辑
}
```
## 5. 清理资源
```c
awk_map_destroy_view(map_id);
awk_uninit();
```
## 完整示例
```c
#include "awk.h"
#include "map/awk_map.h"
int main() {
// 1. 初始化
awk_context_t ctx = {0};
ctx.device_id = "device_001";
ctx.key = "your_key";
ctx.root_dir = "./sdk_data";
// ... 设置适配器
awk_init(&ctx);
// 2. 激活(首次)
awk_device_activate_param_t act = {
.area = "mainland", .country = "cn",
.type = 0, .data_type = "raster"
};
awk_activate_device(&act, callback);
// 3. 创建地图
awk_map_view_param_t vp = {.port = {375, 667}};
uint32_t map_id = awk_map_create_view(vp);
// 4. 渲染循环
while (1) {
awk_map_do_render();
}
// 5. 清理
awk_map_destroy_view(map_id);
awk_uninit();
return 0;
}
```
## 下一步
- [生命周期详解](lifecycle.md) - 了解完整的初始化流程
- [适配器实现](adapters.md) - 实现平台适配器
- [地图操作](map-operations.md) - 控制地图显示
FILE:references/adapter-requirements.md
# 适配器必需函数与错误码
> 基于 `awk.c` 中 `AWK_CHECK_ADAPTER_FUNC` 的完整适配器要求
## 概述
SDK 初始化时会通过 `awk_check_context` 函数检查所有必需的适配器函数是否已实现。如果缺少任何必需函数,初始化将失败并返回对应的错误码。
## 初始化参数检查
在检查适配器函数之前,SDK 会先检查基本参数:
| 参数 | 错误码 | 说明 |
|------|--------|------|
| `context` | -100 | 上下文对象为空 |
| `context->key` | -101 | 高德开放平台 key 未设置 |
| `context->device_id` | -102 | 设备 ID 未设置 |
| `context->root_dir` | -103 | SDK 数据根目录未设置 |
## 渲染适配器 (render_adapter)
### 必需函数
| 函数 | 错误码 | 说明 | 必需条件 |
|------|--------|------|----------|
| `begin_drawing` | -200 | 开始绘制回调 | **始终必需** |
| `commit_drawing` | -201 | 结束绘制回调 | **始终必需** |
| `draw_point` | -202 | 绘制点回调 | **始终必需** |
| `draw_polyline` | -203 | 绘制线回调 | **始终必需** |
| `draw_polygon` | -204 | 绘制面回调 | **始终必需** |
| `draw_bitmap` | -205 | 绘制位图回调 | **始终必需** |
| `draw_color` | -206 | 绘制颜色回调 | **始终必需** |
| `draw_text` | -207 | 绘制文字回调 | **条件必需*** |
| `measure_text` | -208 | 测量文字尺寸回调 | **条件必需*** |
**条件必需说明**:
- 当 `tile_style` 为 `AWK_MAP_TILE_STYLE_GRID_AND_POI` 或 `AWK_MAP_TILE_STYLE_ROAD_AND_POI` 时,`draw_text` 和 `measure_text` 为必需函数
### 函数签名
```c
typedef struct _awk_render_adapter_t {
void (*begin_drawing)(uint32_t map_id, awk_render_context_t context);
void (*commit_drawing)(uint32_t map_id);
void (*draw_point)(uint32_t map_id, awk_point_t *point, uint32_t point_size, const awk_paint_style_t *style);
void (*draw_polyline)(uint32_t map_id, awk_point_t *points, uint32_t point_size, const awk_paint_style_t *style);
void (*draw_polygon)(uint32_t map_id, awk_point_t *points, uint32_t point_size, const awk_paint_style_t *style);
void (*draw_bitmap)(uint32_t map_id, awk_rect_area_t area, awk_bitmap_t bitmap, const awk_paint_style_t *style);
void (*draw_text)(uint32_t map_id, awk_point_t center, const char *text, const awk_paint_style_t *style);
void (*draw_color)(uint32_t map_id, awk_rect_area_t area, const awk_paint_style_t *style);
bool (*measure_text)(uint32_t map_id, const char *text, const awk_paint_style_t *style,
int32_t *width, int32_t *ascender, int32_t *descender);
} awk_render_adapter_t;
```
## 文件适配器 (file_adapter)
### 必需函数
| 函数 | 错误码 | 说明 |
|------|--------|------|
| `file_open` | -300 | 打开文件 |
| `file_close` | -301 | 关闭文件 |
| `file_read` | -302 | 读取文件 |
| `file_write` | -303 | 写入文件 |
| `file_exists` | -304 | 检查文件是否存在 |
| `file_remove` | -305 | 删除文件 |
| `file_dir_exists` | -306 | 检查目录是否存在 |
| `file_mkdir` | -307 | 创建目录 |
| `file_rmdir` | -308 | 删除目录 |
| `file_opendir` | -309 | 打开目录 |
| `file_closedir` | -310 | 关闭目录 |
| `file_readdir` | -311 | 读取目录内容 |
| `file_get_size` | -312 | 获取文件大小 |
| `file_get_last_access` | -313 | 获取文件最后访问时间 |
| `file_rename` | -314 | 重命名文件 |
| `file_seek` | -315 | 文件定位 |
| `file_flush` | -316 | 刷新文件缓冲区 |
### 函数签名
```c
typedef struct _awk_file_adapter_t {
void* (*file_open)(const char *filename, const char *mode);
int (*file_close)(void* handler);
size_t (*file_read)(void *ptr, size_t size, void* handler);
size_t (*file_write)(void *ptr, size_t size, void* handler);
long (*file_tell)(void *handler);
int (*file_seek)(void *handler, long offset, int where);
int (*file_flush)(void *handler);
bool (*file_exists)(const char *path);
int (*file_remove)(const char *path);
bool (*file_dir_exists)(const char *path);
int (*file_mkdir)(const char *path, uint16_t model);
int (*file_rmdir)(const char *path);
void* (*file_opendir)(const char *path);
int (*file_closedir)(void *dir);
bool (*file_readdir)(void *dir, awk_readdir_result *result);
size_t (*file_get_size)(const char *path);
long (*file_get_last_access)(const char *path);
int (*file_rename)(const char *old_name, const char *new_name);
bool (*file_unzip)(const char *zip_file, const char *out_dir);
} awk_file_adapter_t;
```
## 内存适配器 (memory_adapter)
### 必需函数
| 函数 | 错误码 | 说明 |
|------|--------|------|
| `mem_malloc` | -400 | 分配内存 |
| `mem_free` | -401 | 释放内存 |
| `mem_calloc` | -402 | 分配并清零内存 |
| `mem_realloc` | -403 | 重新分配内存 |
### 函数签名
```c
typedef struct _awk_memory_adapter_t {
void (*mem_free)(void* ptr);
void* (*mem_malloc)(size_t size);
void* (*mem_calloc)(size_t count, size_t size);
void* (*mem_realloc)(void* ptr, size_t size);
} awk_memory_adapter_t;
```
## 系统适配器 (system_adapter)
### 必需函数
| 函数 | 错误码 | 说明 |
|------|--------|------|
| `get_system_time` | -500 | 获取系统时间(毫秒) |
| `log_printf` | -501 | 日志输出 |
### 函数签名
```c
typedef struct _awk_system_adapter_t {
uint64_t (*get_system_time)(void);
int (*log_printf)(const char* __fmt, ...);
} awk_system_adapter_t;
```
## 网络适配器 (network_adapter)
### 必需函数
| 函数 | 错误码 | 说明 |
|------|--------|------|
| `send` | -600 | 发送 HTTP 请求 |
| `cancel` | -601 | 取消 HTTP 请求 |
### 函数签名
```c
typedef struct _awk_network_adapter_t {
uint64_t (*send)(awk_http_request_t *request, awk_http_response_callback_t *callback);
void (*cancel)(uint64_t request_id);
} awk_network_adapter_t;
```
**重要说明**:
- 网络请求可以在异步线程中处理
- 但回调 SDK 时**必须切回主线程**
## 线程适配器 (thread_adapter)
### 必需函数
| 函数 | 错误码 | 说明 |
|------|--------|------|
| `get_thread_id` | -701 | 获取当前线程 ID |
### 函数签名
```c
typedef struct _awk_thread_adapter_t {
uint64_t (*get_thread_id)(void);
} awk_thread_adapter_t;
```
## 瓦片文件适配器 (tile_file_adapter)
### 必需函数
| 函数 | 错误码 | 说明 | 必需条件 |
|------|--------|------|----------|
| `on_tile_file` | -800 | 加载瓦片文件回调 | **条件必需*** |
**条件必需说明**:
- 当 `tile_style` 为 `AWK_MAP_TILE_STYLE_GRID_AND_POI` 或 `AWK_MAP_TILE_STYLE_ROAD_AND_POI` 时为必需函数
### 函数签名
```c
typedef struct _awk_map_tile_file_adapter_t {
bool (*on_tile_file)(const char* tile_file_key, char *file_path, size_t *file_offset, size_t *file_size);
} awk_map_tile_file_adapter_t;
```
## 完整错误码列表
### 基本参数错误 (-100 ~ -103)
| 错误码 | 说明 |
|--------|------|
| -100 | 上下文对象为空 |
| -101 | 高德开放平台 key 未设置 |
| -102 | 设备 ID 未设置 |
| -103 | SDK 数据根目录未设置 |
### 渲染适配器错误 (-200 ~ -208)
| 错误码 | 缺失函数 |
|--------|----------|
| -200 | `render_adapter.begin_drawing` |
| -201 | `render_adapter.commit_drawing` |
| -202 | `render_adapter.draw_point` |
| -203 | `render_adapter.draw_polyline` |
| -204 | `render_adapter.draw_polygon` |
| -205 | `render_adapter.draw_bitmap` |
| -206 | `render_adapter.draw_color` |
| -207 | `render_adapter.draw_text` (条件必需) |
| -208 | `render_adapter.measure_text` (条件必需) |
### 文件适配器错误 (-300 ~ -316)
| 错误码 | 缺失函数 |
|--------|----------|
| -300 | `file_adapter.file_open` |
| -301 | `file_adapter.file_close` |
| -302 | `file_adapter.file_read` |
| -303 | `file_adapter.file_write` |
| -304 | `file_adapter.file_exists` |
| -305 | `file_adapter.file_remove` |
| -306 | `file_adapter.file_dir_exists` |
| -307 | `file_adapter.file_mkdir` |
| -308 | `file_adapter.file_rmdir` |
| -309 | `file_adapter.file_opendir` |
| -310 | `file_adapter.file_closedir` |
| -311 | `file_adapter.file_readdir` |
| -312 | `file_adapter.file_get_size` |
| -313 | `file_adapter.file_get_last_access` |
| -314 | `file_adapter.file_rename` |
| -315 | `file_adapter.file_seek` |
| -316 | `file_adapter.file_flush` |
### 内存适配器错误 (-400 ~ -403)
| 错误码 | 缺失函数 |
|--------|----------|
| -400 | `memory_adapter.mem_malloc` |
| -401 | `memory_adapter.mem_free` |
| -402 | `memory_adapter.mem_calloc` |
| -403 | `memory_adapter.mem_realloc` |
### 系统适配器错误 (-500 ~ -501)
| 错误码 | 缺失函数 |
|--------|----------|
| -500 | `system_adapter.get_system_time` |
| -501 | `system_adapter.log_printf` |
### 网络适配器错误 (-600 ~ -601)
| 错误码 | 缺失函数 |
|--------|----------|
| -600 | `network_adapter.send` |
| -601 | `network_adapter.cancel` |
### 线程适配器错误 (-701)
| 错误码 | 缺失函数 |
|--------|----------|
| -701 | `thread_adapter.get_thread_id` |
### 瓦片文件适配器错误 (-800)
| 错误码 | 缺失函数 |
|--------|----------|
| -800 | `tile_file_adapter.on_tile_file` (条件必需) |
## 检查流程
SDK 初始化时的检查流程如下:
```c
int32_t awk_init(awk_context_t *context) {
// 1. 检查是否已初始化
if (s_inited) {
return -1;
}
// 2. 检查上下文和适配器
int32_t re = awk_check_context(context);
if (re != 0) {
return re; // 返回具体的错误码
}
// 3. 继续初始化流程
// ...
}
```
## 最佳实践
### 1. 初始化前检查
```c
awk_context_t context = {0};
// 设置基本参数
context.key = "your_amap_key";
context.device_id = "your_device_id";
context.root_dir = "/path/to/sdk/data";
// 设置所有必需的适配器函数
context.render_adapter.begin_drawing = my_begin_drawing;
context.render_adapter.commit_drawing = my_commit_drawing;
// ... 设置其他所有必需函数
// 初始化
int32_t ret = awk_init(&context);
if (ret != 0) {
// 根据错误码定位问题
switch (ret) {
case -100:
printf("错误:上下文对象为空\n");
break;
case -101:
printf("错误:未设置高德开放平台 key\n");
break;
case -200:
printf("错误:未实现 render_adapter.begin_drawing\n");
break;
// ... 处理其他错误码
default:
printf("初始化失败,错误码:%d\n", ret);
}
}
```
### 2. 条件必需函数处理
```c
// 如果使用带 POI 的瓦片样式
if (context.tile_style == AWK_MAP_TILE_STYLE_GRID_AND_POI ||
context.tile_style == AWK_MAP_TILE_STYLE_ROAD_AND_POI) {
// 必须实现文字相关函数
context.render_adapter.draw_text = my_draw_text;
context.render_adapter.measure_text = my_measure_text;
// 必须实现瓦片文件加载函数
context.tile_file_adapter.on_tile_file = my_on_tile_file;
}
```
### 3. 错误处理建议
```c
const char* get_error_message(int32_t error_code) {
switch (error_code) {
case -100: return "上下文对象为空";
case -101: return "未设置高德开放平台 key";
case -102: return "未设置设备 ID";
case -103: return "未设置 SDK 数据根目录";
case -200: return "未实现 render_adapter.begin_drawing";
case -201: return "未实现 render_adapter.commit_drawing";
// ... 添加所有错误码的描述
default: return "未知错误";
}
}
```
## 注意事项
1. **所有必需函数都必须实现**,否则初始化会失败
2. **条件必需函数**根据 `tile_style` 决定是否必需
3. **线程安全**:所有 SDK 方法必须在主线程调用
4. **网络回调**:网络请求可异步处理,但回调 SDK 时必须切回主线程
5. **错误码范围**:
- -100 ~ -103:基本参数错误
- -200 ~ -299:渲染适配器错误
- -300 ~ -399:文件适配器错误
- -400 ~ -499:内存适配器错误
- -500 ~ -599:系统适配器错误
- -600 ~ -699:网络适配器错误
- -700 ~ -799:线程适配器错误
- -800 ~ -899:瓦片文件适配器错误
## 相关文档
- [适配器实现](../api/adapters.md) - 适配器实现示例
- [iOS 集成指南](../api/ios-integration.md) - iOS 平台适配器实现
- [错误码](error-codes.md) - 完整错误码说明
FILE:references/core-types.md
# 核心类型定义
> 关键数据结构参考
## 基础类型
### 坐标点
```c
// 经纬度坐标(GCJ02)
typedef struct {
double lon; // 经度
double lat; // 纬度
} awk_map_coord2d_t;
// 屏幕坐标(左上角为原点)
typedef struct {
float x;
float y;
} awk_point_t;
```
### 矩形区域
```c
typedef struct {
float x; // 左上角 x
float y; // 左上角 y
float width; // 宽度(像素)
float height; // 高度(像素)
} awk_rect_area_t;
```
### 位图
```c
typedef struct {
awk_pixel_mode_t pixel_mode; // 像素格式
uint8_t *buffer; // 数据缓冲区
uint32_t buffer_size; // 缓冲区大小
uint32_t width; // 宽度(像素)
uint32_t height; // 高度(像素)
uint32_t stride; // 每像素字节数
bool pre_multiplied; // 是否预乘 alpha
} awk_bitmap_t;
```
---
## 像素格式
```c
typedef enum {
AWK_PIXEL_MODE_GREY, // 8位灰度
AWK_PIXEL_MODE_RGB_332, // 8位 RGB
AWK_PIXEL_MODE_RGB_565, // 16位 RGB
AWK_PIXEL_MODE_RGB_888, // 24位 RGB
AWK_PIXEL_MODE_ARGB_8888, // 32位 ARGB
AWK_PIXEL_MODE_RGBA_8888, // 32位 RGBA
AWK_PIXEL_MODE_BGR_233, // 8位 BGR
AWK_PIXEL_MODE_BGR_565, // 16位 BGR
AWK_PIXEL_MODE_BGR_888, // 24位 BGR
AWK_PIXEL_MODE_BGRA_8888, // 32位 BGRA
AWK_PIXEL_MODE_ABGR_8888, // 32位 ABGR
} awk_pixel_mode_t;
```
**字节顺序说明:**
| 格式 | 字节数 | 字节顺序 |
|------|--------|----------|
| RGB_565 | 2 | 字节0: G[2:0]+B[4:0], 字节1: R[4:0]+G[5:3] |
| RGB_888 | 3 | R, G, B |
| ARGB_8888 | 4 | A, R, G, B |
| RGBA_8888 | 4 | R, G, B, A |
---
## 地图相关
### 地图视口
```c
typedef struct {
int32_t width;
int32_t height;
} awk_map_view_port_t;
typedef struct {
awk_map_view_port_t port;
} awk_map_view_param_t;
```
### 地图姿态
```c
typedef struct {
awk_map_coord2d_t center; // 中心点
float level; // 缩放级别 (3-20)
float roll_angle; // 旋转角度 (0-360)
} awk_map_posture_t;
```
### 瓦片加载模式
```c
typedef enum {
AWK_MAP_TILE_LOAD_MODE_OFFLINE, // 离线
AWK_MAP_TILE_LOAD_MODE_ONLINE, // 在线
AWK_MAP_TILE_LOAD_MODE_MIXED, // 混合
} awk_map_tile_load_mode_t;
```
### 瓦片样式
```c
typedef enum {
AWK_MAP_TILE_STYLE_NORMAL, // 标准
AWK_MAP_TILE_STYLE_DARK, // 暗色
} awk_map_tile_style_t;
```
---
## 覆盖物相关
### 基础覆盖物
```c
typedef struct {
int32_t guid; // 唯一标识
awk_map_geometry_type_t type; // 几何类型
int32_t z_index; // 层级
bool visible; // 是否可见
} awk_map_base_overlay_t;
```
### 点覆盖物
```c
typedef struct {
awk_map_base_overlay_t base;
awk_map_coord2d_t position; // 位置
awk_map_point_marker_t normal_marker; // 普通状态样式
awk_map_point_marker_t selected_marker; // 选中状态样式
} awk_map_point_overlay_t;
```
### 线覆盖物
```c
typedef struct {
awk_map_base_overlay_t base;
awk_map_coord2d_t *points; // 坐标点数组
uint32_t point_size; // 点数量
awk_map_line_marker_t normal_marker;
} awk_map_polyline_overlay_t;
```
### 面覆盖物
```c
typedef struct {
awk_map_base_overlay_t base;
awk_map_coord2d_t *points; // 坐标点数组
uint32_t point_size; // 点数量
uint32_t color; // 填充颜色 (ARGB)
} awk_map_polygon_overlay_t;
```
---
## 绘制样式
### 画笔样式
```c
typedef struct {
uint32_t width; // 画笔宽度(像素)
uint32_t color; // 颜色 (ARGB)
float angle; // 旋转角度 [0-360)
awk_text_style_t text_style;
awk_fill_style_t fill_style;
awk_dash_style_t dash_style;
} awk_paint_style_t;
```
### 文字样式
```c
typedef struct {
awk_align_style_t align; // 对齐方式
uint32_t font_size; // 字号
awk_font_weight_t font_weight; // 字重
} awk_text_style_t;
typedef enum {
AWK_ALIGN_STYLE_NONE,
AWK_ALIGN_STYLE_CENTER,
AWK_ALIGN_STYLE_LEFT,
AWK_ALIGN_STYLE_RIGHT
} awk_align_style_t;
typedef enum {
AWK_FONT_WEIGHT_NORMAL,
AWK_FONT_WEIGHT_THIN,
AWK_FONT_WEIGHT_BOLD
} awk_font_weight_t;
```
### 虚线样式
```c
typedef struct {
int32_t painted_length; // 绘制长度(像素)
int32_t unpainted_length; // 空白长度(像素)
int32_t offset; // 起始偏移
} awk_dash_style_t;
```
### 填充样式
```c
typedef enum {
AWK_FILL_STYLE_DRAWING_ONLY, // 仅填充
AWK_FILL_STYLE_DRAWING_AND_STROKE, // 填充+描边
AWK_FILL_STYLE_STROKE_ONLY // 仅描边
} awk_fill_style_t;
```
---
## 导航相关
### 导航信息
```c
typedef struct {
awk_navi_mode_t navi_mode; // 导航模式
uint32_t remain_distance; // 剩余距离(米)
uint32_t remain_time; // 剩余时间(秒)
// ...
} awk_navi_info_t;
```
### 导航位置
```c
typedef struct {
awk_map_coord2d_t position; // 当前位置
float speed; // 速度
float direction; // 方向
} awk_navi_location_t;
```
### 转向图标类型
```c
typedef enum {
AWK_NAVI_ICON_STRAIGHT, // 直行
AWK_NAVI_ICON_TURN_LEFT, // 左转
AWK_NAVI_ICON_TURN_RIGHT, // 右转
AWK_NAVI_ICON_UTURN, // 掉头
// ...
} awk_navi_icon_type;
```
## 下一步
- [错误码](error-codes.md) - 错误码说明
- [常见问题](troubleshooting.md) - FAQ
FILE:references/error-codes.md
# 错误码说明
> SDK 返回值与错误码参考
## 通用错误码
| 错误码 | 说明 | 处理建议 |
|--------|------|----------|
| 0 | 成功 | - |
| -1 | 未初始化 | 先调用 `awk_init()` |
| -2 | 资源不存在 | 检查 ID 是否正确 |
| -3 | 线程不一致 | 确保在主线程调用 |
| -4 | 参数错误 | 检查参数有效性 |
---
## 初始化错误码
### awk_init 返回值
| 错误码 | 说明 |
|--------|------|
| -1 | 已初始化,不能重复初始化 |
| -100 | context 为空 |
| -101 | key 为空 |
| -102 | device_id 为空 |
| -103 | root_dir 为空 |
| -2xx | render_adapter 函数指针为空 |
| -3xx | file_adapter 函数指针为空 |
| -4xx | memory_adapter 函数指针为空 |
| -5xx | system_adapter 函数指针为空 |
| -6xx | network_adapter 函数指针为空 |
| -7xx | thread_adapter 函数指针为空 |
| -8xx | tile_file_adapter 函数指针为空 |
---
## 设备激活错误码
| 错误码 | 说明 | 处理建议 |
|--------|------|----------|
| 30046 | license 数量超限 | 联系商务扩容 |
| 30047 | license 已存在 | 无需重复激活 |
| 30048 | license 已禁用 | 联系商务处理 |
| 30049 | license 超过有效期 | 续约 license |
---
## 地图操作错误码
### awk_map_create_view
| 返回值 | 说明 |
|--------|------|
| >0 | 成功,返回地图 ID |
| -1 | 未初始化 |
| -2 | license 校验失败 |
| -3 | 线程不一致 |
### awk_map_add_overlay
| 返回值 | 说明 |
|--------|------|
| 0 | 成功 |
| -1 | 未初始化 |
| -2 | guid 已存在 |
| -3 | overlay 为空或类型错误 |
| -4 | 线程不一致 |
### awk_map_set_level
| 返回值 | 说明 |
|--------|------|
| 0 | 成功 |
| -1 | 未初始化 |
| -3 | 线程不一致 |
| -4 | level 不合法(超出 3-20 范围)|
---
## 导航错误码
### awk_navi_data
| 返回值 | 说明 | 处理建议 |
|--------|------|----------|
| 0 | 成功 | - |
| -2 | 数据解析失败 | 重传数据 |
| -7 | 数据不完整 | 重传数据 |
| -20 | 数据校验失败 | 重传数据 |
| -10000 | 外层数据结构异常 | 检查数据格式 |
| -10001 | 反初始化后调用 | 重新初始化 |
---
## 瓦片下载状态
```c
typedef enum {
AWK_MAP_TILE_RESPONSE_SUCCESS, // 成功
AWK_MAP_TILE_RESPONSE_NETWORK_ERROR, // 网络错误
AWK_MAP_TILE_RESPONSE_NOT_FOUND, // 瓦片不存在
AWK_MAP_TILE_RESPONSE_TIMEOUT, // 超时
AWK_MAP_TILE_RESPONSE_CANCELLED, // 已取消
} awk_map_tile_response_status_t;
```
---
## 错误处理示例
```c
int32_t result = awk_init(&context);
switch (result) {
case 0:
printf("初始化成功\n");
break;
case -1:
printf("错误:已初始化,不能重复初始化\n");
break;
case -100:
printf("错误:context 为空\n");
break;
case -101:
printf("错误:key 为空\n");
break;
default:
if (result <= -200 && result > -300) {
printf("错误:render_adapter 不完整\n");
} else if (result <= -300 && result > -400) {
printf("错误:file_adapter 不完整\n");
}
break;
}
```
## 下一步
- [常见问题](troubleshooting.md) - FAQ 与问题排查
FILE:references/troubleshooting.md
# 常见问题
> FAQ 与问题排查指南
## 初始化问题
### Q: 初始化返回 -1xx 错误
**原因**:必填参数缺失
**解决**:
```c
awk_context_t context;
memset(&context, 0, sizeof(awk_context_t)); // 务必先 memset
context.device_id = "xxx"; // 必填
context.key = "xxx"; // 必填
context.root_dir = "xxx"; // 必填
```
### Q: 初始化返回 -2xx/-3xx/-4xx 错误
**原因**:适配器函数指针未设置
**解决**:确保所有必需适配器的函数指针都已设置:
- `-2xx`:检查 `render_adapter`
- `-3xx`:检查 `file_adapter`
- `-4xx`:检查 `memory_adapter`
- `-5xx`:检查 `system_adapter`
- `-6xx`:检查 `network_adapter`
---
## 激活问题
### Q: 激活失败,返回 30046
**原因**:license 数量超限
**解决**:联系商务扩容或清理无用设备
### Q: 激活失败,返回 30049
**原因**:license 过期
**解决**:
1. 检查设备时间是否正确
2. 联系商务续约
### Q: 离线环境无法激活
**原因**:激活需要联网
**解决**:
1. 首次激活必须联网
2. 激活成功后可离线使用
3. 可使用 `awk_check_device_activated()` 检查激活状态
---
## 渲染问题
### Q: 地图不显示
**排查步骤**:
1. 检查 `awk_map_create_view()` 返回值是否 > 0
2. 确认 `awk_map_do_render()` 在主循环中定时调用
3. 检查 `render_adapter` 实现是否正确
4. 确认设备已激活
### Q: 地图显示异常/闪烁
**原因**:多线程调用
**解决**:确保所有 SDK 方法在同一主线程调用
### Q: 瓦片加载失败
**排查步骤**:
1. 检查网络连接(在线模式)
2. 检查离线地图路径(离线模式)
3. 检查 `network_adapter` 实现
4. 查看 `on_tile_end_download` 回调状态
---
## 覆盖物问题
### Q: 覆盖物不显示
**排查步骤**:
1. 检查 `awk_map_add_overlay()` 返回值
2. 确认坐标在当前地图可视范围内
3. 检查 `visible` 属性是否为 `true`
4. 检查 `z_index` 层级
### Q: 添加覆盖物返回 -2
**原因**:guid 重复
**解决**:确保每个覆盖物的 guid 唯一
### Q: 线/面覆盖物内存泄漏
**原因**:未释放坐标点数组
**解决**:
```c
// 添加后释放
awk_map_add_overlay(bindmap_id, bindoverlay);
free(bindoverlay->points); // 释放坐标数组
```
---
## 导航问题
### Q: 导航数据回调不触发
**排查步骤**:
1. 确认已调用 `awk_navi_add_data_callback()`
2. 检查 `awk_navi_data()` 返回值
3. 确认 PB 数据格式正确
### Q: awk_navi_data 返回负数
| 返回值 | 处理 |
|--------|------|
| -2, -7, -20 | 重传数据 |
| -10000 | 检查数据格式 |
| -10001 | 重新初始化导航 |
### Q: 导航地图操作无效
**原因**:导航模式下内部控制地图
**解决**:导航中不要外部操作地图(缩放、旋转等)
---
## 性能问题
### Q: 内存占用过高
**解决**:
1. 减小 `tile_mem_cache_max_size`
2. 定期调用 `awk_clear_memory_cache()`
3. 减少覆盖物数量
### Q: 渲染卡顿
**解决**:
1. 降低渲染频率
2. 减少覆盖物数量
3. 使用较低的瓦片精细度 `poi_tile_density`
---
## 调试技巧
### 启用日志
```c
context.system_adapter.log_printf = my_log_function;
```
### 检查激活状态
```c
if (!awk_check_device_activated(¶m, &context)) {
// 需要激活
awk_activate_device(¶m, callback);
}
```
### 监控瓦片下载
```c
awk_map_render_callback_t cb = {
.on_tile_end_download = on_tile_download_complete
};
void on_tile_download_complete(int32_t type, uint32_t x, uint32_t y,
uint32_t zoom, awk_map_tile_response_status_t status) {
if (status != AWK_MAP_TILE_RESPONSE_SUCCESS) {
printf("瓦片下载失败: %d/%d/%d, status=%d\n", zoom, x, y, status);
}
}
```
## 获取帮助
如问题仍未解决,请提供:
1. SDK 版本
2. 设备信息
3. 错误码/日志
4. 复现步骤
Map Agent - 高德地图 MALLMKit SDK 集成技能,支持自然语言查询、Map 路线规划、POI搜索、导航控制等智能 Map 地图服务,以及与高德 Map APP 的 IPC 通信
---
name: ios-llm-agent-sdk
display_name: Map Agent - iOS LLM Agent SDK(高德官方 AI Agent Skill)
version: 1.0.2
description: Map Agent - 高德地图 MALLMKit SDK 集成技能,支持自然语言查询、Map 路线规划、POI搜索、导航控制等智能 Map 地图服务,以及与高德 Map APP 的 IPC 通信
author: 高德开放平台
tags:
- 地图
- 高德
- Map
- iOS
- LLM
- Agent
- SDK
- AMap
---
# Map Agent - iOS LLM Agent SDK(高德官方 AI Agent Skill)
高德地图 MALLMKit SDK 集成技能,支持自然语言查询、路线规划、POI搜索、导航控制等智能地图服务,以及与高德地图 APP 的 IPC 通信(授权认证、建联、收发数据)。
## 适用场景
- 集成高德智能语音助手到 iOS 应用
- 实现自然语言驱动的地图交互(如"去西藏"、"附近的肯德基")
- 导航控制与数据监听
- 合作方 APP 与高德地图 APP 建立 IPC 通信链路,收发数据
## 触发词
| 触发词 | 文档 | 说明 |
|--------|------|------|
| **接入LLM Agent SDK** | [接入 Agent](api/integrate-agent.md) | Agent 初始化、命令注册、查询调用完整流程 |
| **链接高德app** | [链接高德 APP](api/link-quick-start.md) | Link 页面创建、授权认证、建联、导航命令收发完整流程 |
> 💡 别名:说"接入agent"或"接入agent sdk"也会匹配到"接入LLM Agent SDK"触发词。
> 💡 别名:说"连接高德app"、"接入linkKit"、"IPC通信"、"与高德APP通信"也会匹配到"链接高德app"触发词。
## 快速开始
- Agent SDK 首次接入请阅读:[快速集成指南](api/quick-start.md)
- Link SDK 首次接入请阅读:[Link 快速集成指南](api/link-quick-start.md)
## API 文档 — Agent SDK(按需查阅)
| 文档 | 说明 |
|------|------|
| [智能查询](api/agent-query.md) | 发起自然语言查询、多轮对话 |
| [查询结果处理](api/query-result.md) | 处理路线、POI、导航等查询结果 |
| [导航控制](api/navi-control.md) | 开始/停止导航、切换路线、播报模式 |
| [导航数据监听](api/navi-data-listener.md) | 实时监听导航数据回调 |
| [出行方式配置](api/transport-mode.md) | 导航环境、路线偏好、家/公司位置 |
| [IPC链路管理](api/link-client.md) | APP链路模式的建联与授权 |
| [生命周期管理](api/lifecycle.md) | 场景管理、状态重置、内存管理 |
| [日志管理](api/logger.md) | SDK 内部日志监听 |
## API 文档 — Link SDK(按需查阅)
| 文档 | 说明 |
|------|------|
| [认证管理](api/authorization.md) | 通过 AMapAuthorizationManager 完成授权流程与回调处理 |
| [连接管理](api/connection.md) | 通过 AMapLinkManager 建立连接、状态监听、自动重连、断开连接 |
| [数据传输与命令](api/data-transfer.md) | 发送数据、导航命令(途经点/目的地/播报/开始导航)、数据监听 |
## 参考文档(深入查阅)
| 文档 | 说明 |
|------|------|
| [Agent 核心类参考](references/core-classes.md) | Agent SDK 公共类与枚举速查 |
| [常见问题排查](references/troubleshooting.md) | 错误码与常见问题解决 |
| [语音指令参考](references/voice-commands.md) | 支持的自然语言指令示例 |
| [Link 核心类参考](references/link-core-classes.md) | Link SDK 公共类速查 |
| [Link 错误码参考](references/link-error-codes.md) | Link SDK 错误码速查 |
FILE:README.md
# iOS LLM Agent SDK (MALLMKit) Skills User Guide
[🇨🇳 中文文档](./README_zh.md) | [⬆️ Back to Home](../README.md)
## Product Introduction
**AMap iOS LLM Agent SDK Skills** (MALLMKit) is an AI programming skill package designed for AI IDEs. It integrates the official documentation, best practices, and code templates of the AMap MALLMKit SDK for iOS into structured skill files, enabling AI coding tools like Cursor, Claude, and Cline to:
- **Accurately understand** how to integrate intelligent map services into iOS applications
- **Automatically generate** Agent initialization, query, navigation control, and IPC communication code
- **Proactively avoid** common integration issues such as authorization failures and connection management
- **Provide** verified code examples for both Agent SDK and Link SDK features
## Product Features
### Intelligent Map Services
Supports natural language queries for route planning, POI search, navigation control, and more. Users can interact with maps using natural language like "Go to Tibet" or "Find nearby KFC".
### Dual SDK Architecture
Includes both Agent SDK (for AI Agent-powered map interactions) and Link SDK (for communication with AMap APP), providing comprehensive integration capabilities.
### Complete Navigation Control
Full navigation lifecycle management including start/stop navigation, route switching, broadcast mode control, and real-time navigation data monitoring.
### IPC Communication
Robust IPC communication framework with AMap APP, supporting authorization, connection management, data transfer, and navigation commands.
## Capabilities
### Agent SDK
| **Capability** | **Description** |
| --- | --- |
| Intelligent Query | Natural language queries for routes, POI, navigation |
| Query Result Handling | Process AI responses with structured data |
| Navigation Control | Start/stop navigation, switch routes, broadcast mode |
| Navigation Data Listener | Real-time navigation data callbacks |
| Transport Mode | Navigation environment and route preference configuration |
| Lifecycle Management | Scene management, state reset, memory cleanup |
### Link SDK
| **Capability** | **Description** |
| --- | --- |
| Authorization | AMapAuthorizationManager for auth flow and callbacks |
| Connection Management | AMapLinkManager for connection, status monitoring, auto-reconnect |
| Data Transfer | Send data, navigation commands (waypoints, destination, broadcast, start navigation) |
| Navigation Commands | Waypoint/destination setting, broadcast control, navigation start |
### Reference
| **Capability** | **Description** |
| --- | --- |
| Agent Core Classes | Agent SDK public classes and enum reference |
| Link Core Classes | Link SDK public classes reference |
| Link Error Codes | Link SDK error code reference |
| Voice Commands | Supported natural language command examples |
| Troubleshooting | Error codes and common issue resolution |
## Quick Start
### Step 1: Configure Skill in Cursor
```bash
# Link the iOS LLM Agent skill to your project
ln -s /path/to/open_sdk_skills/ios-llm-agent-sdk .cursor/skills/ios-llm-agent-sdk
```
### Step 2: Verify Configuration
Open Cursor AI Chat and enter:
**For Agent SDK:**
```text
Help me integrate MALLMKit SDK into my iOS app and implement a natural language map query
```
**For Link SDK:**
```text
Help me set up IPC communication with AMap APP using the Link SDK, including authorization and connection management
```
If AI correctly references the Skill files and generates complete integration code, the Skill has been successfully loaded.
### Step 3: Choose Your Integration Path
- **Agent SDK**: For AI-powered map interactions → Start with [Quick Start](api/quick-start.md) or [Integrate Agent](api/integrate-agent.md)
- **Link SDK**: For IPC communication with AMap APP → Start with [Link Quick Start](api/link-quick-start.md)
## Usage Examples
### Example 1: Agent Initialization
```text
Initialize MALLMKit Agent SDK in my iOS app, register navigation commands, and set up query callbacks
```
### Example 2: Natural Language Query
```text
Send a natural language query "Find the nearest gas station and navigate there" and handle the route planning result
```
### Example 3: Navigation Control
```text
Implement navigation control with start/stop, route switching, and real-time navigation data display
```
### Example 4: Link SDK Integration
```text
Set up Link SDK to communicate with AMap APP, implement authorization flow, establish connection, and send navigation commands
```
## Directory Structure
```text
ios-llm-agent-sdk/
├── SKILL.md # Main skill file (AI entry point)
├── api/ # API guides
│ ├── quick-start.md # Agent SDK quick start
│ ├── integrate-agent.md # Complete Agent integration flow
│ ├── agent-query.md # Natural language queries
│ ├── query-result.md # Query result handling
│ ├── navi-control.md # Navigation control
│ ├── navi-data-listener.md # Navigation data listener
│ ├── transport-mode.md # Transport mode configuration
│ ├── link-quick-start.md # Link SDK quick start
│ ├── link-client.md # LinkClient management
│ ├── authorization.md # Authorization management
│ ├── connection.md # Connection management
│ ├── data-transfer.md # Data transfer and commands
│ ├── logger.md # Logger configuration
│ └── lifecycle.md # Lifecycle management
└── references/ # Reference documentation
├── core-classes.md # Agent SDK core classes
├── link-core-classes.md # Link SDK core classes
├── link-error-codes.md # Link SDK error codes
├── troubleshooting.md # Troubleshooting guide
└── voice-commands.md # Voice command examples
```
## FAQ
### Q: Agent query returns no result
**A:** Check that:
1. Agent SDK is properly initialized with correct API key
2. Network connection is available
3. Query format follows the supported patterns (see [Voice Commands](references/voice-commands.md))
### Q: Link SDK authorization fails
**A:** Ensure:
1. AMap APP is installed on the device
2. Authorization configuration is correct
3. Check error codes in [Link Error Codes](references/link-error-codes.md)
### Q: Navigation data listener not receiving callbacks
**A:** Verify:
1. Navigation is properly started
2. Data listener is registered before navigation starts
3. Location permissions are granted
### Q: Connection with AMap APP drops frequently
**A:** Check:
1. Auto-reconnect is enabled in AMapLinkManager
2. Both apps are in the foreground or have background mode enabled
3. Review connection status monitoring implementation
## Related Links
- [AMap Open Platform Console](https://console.amap.com/)
- [Cursor Official Documentation](https://docs.cursor.com/)
- [⬆️ Back to Home](../README.md)
FILE:README_zh.md
# iOS LLM Agent SDK (MALLMKit) Skills 使用文档
[⬆️ 返回首页](../README_zh.md)
## 产品介绍
**高德 iOS LLM Agent SDK Skills**(MALLMKit)是一套专为 AI IDE 设计的 AI 编程技能包。它将高德 MALLMKit SDK(iOS 版)的官方文档、最佳实践和代码模板整合为结构化的技能文件,使 Cursor、Claude、Cline 等 AI Coding 工具能够:
- **精准理解**如何将智能地图服务集成到 iOS 应用中
- **自动生成** Agent 初始化、查询、导航控制和 IPC 通信代码
- **主动避免**常见的授权失败和连接管理等集成问题
- **提供**经过验证的 Agent SDK 和 Link SDK 功能代码示例
## 产品特点
### 智能地图服务
支持自然语言查询路线规划、POI 搜索、导航控制等功能。用户可以使用自然语言与地图交互,如"去西藏"、"附近的肯德基"。
### 双 SDK 架构
包含 Agent SDK(AI Agent驱动的地图交互)和 Link SDK(与高德 APP 进行通信),提供全面的集成能力。
### 完整的导航控制
完整的导航生命周期管理,包括开始/停止导航、路线切换、播报模式控制和实时导航数据监听。
### IPC 通信
与高德 APP 的健壮 IPC 通信框架,支持授权认证、连接管理、数据传输和导航命令。
## 能力介绍
### Agent SDK
| **能力** | **说明** |
| --- | --- |
| 智能查询 | 自然语言查询路线、POI、导航 |
| 查询结果处理 | 处理 AI 返回的结构化数据 |
| 导航控制 | 开始/停止导航、切换路线、播报模式 |
| 导航数据监听 | 实时导航数据回调 |
| 出行方式 | 导航环境与路线偏好配置 |
| 生命周期管理 | 场景管理、状态重置、内存管理 |
### Link SDK
| **能力** | **说明** |
| --- | --- |
| 认证管理 | 通过 AMapAuthorizationManager 完成授权流程与回调处理 |
| 连接管理 | 通过 AMapLinkManager 建立连接、状态监听、自动重连 |
| 数据传输 | 发送数据、导航命令(途经点/目的地/播报/开始导航) |
| 导航命令 | 途经点/目的地设置、播报控制、导航启动 |
### 参考资料
| **能力** | **说明** |
| --- | --- |
| Agent 核心类 | Agent SDK 公共类与枚举速查 |
| Link 核心类 | Link SDK 公共类速查 |
| Link 错误码 | Link SDK 错误码速查 |
| 语音指令 | 支持的自然语言指令示例 |
| 问题排查 | 错误码与常见问题解决 |
## 快速接入
### 第一步:在 Cursor 中配置 Skill
```bash
# 将 iOS LLM Agent Skill 链接到您的项目
ln -s /path/to/open_sdk_skills/ios-llm-agent-sdk .cursor/skills/ios-llm-agent-sdk
```
### 第二步:验证配置
打开 Cursor AI Chat,输入:
**Agent SDK 测试:**
```text
帮我将 MALLMKit SDK 集成到 iOS 应用中,实现一个自然语言地图查询
```
**Link SDK 测试:**
```text
帮我使用 Link SDK 建立与高德 APP 的 IPC 通信,包括授权和连接管理
```
如果 AI 能够正确引用 Skill 文件并生成完整的集成代码,说明 Skill 已成功加载。
### 第三步:选择集成路径
- **Agent SDK**:AI 驱动的地图交互 → 从 [快速开始](api/quick-start.md) 或 [接入 Agent](api/integrate-agent.md) 开始
- **Link SDK**:与高德 APP 的 IPC 通信 → 从 [Link 快速开始](api/link-quick-start.md) 开始
## 使用示例
### 示例 1:Agent 初始化
```text
在 iOS 应用中初始化 MALLMKit Agent SDK,注册导航命令并设置查询回调
```
### 示例 2:自然语言查询
```text
发送自然语言查询"找到最近的加油站并导航过去",并处理路径规划结果
```
### 示例 3:导航控制
```text
实现导航控制功能,包括开始/停止、路线切换和实时导航数据展示
```
### 示例 4:Link SDK 集成
```text
配置 Link SDK 与高德 APP 通信,实现授权流程、建立连接并发送导航命令
```
## 目录结构
```text
ios-llm-agent-sdk/
├── SKILL.md # 技能主文件(AI 入口)
├── api/ # API 使用指南
│ ├── quick-start.md # Agent SDK 快速开始
│ ├── integrate-agent.md # 完整 Agent 集成流程
│ ├── agent-query.md # 自然语言查询
│ ├── query-result.md # 查询结果处理
│ ├── navi-control.md # 导航控制
│ ├── navi-data-listener.md # 导航数据监听
│ ├── transport-mode.md # 出行方式配置
│ ├── link-quick-start.md # Link SDK 快速开始
│ ├── link-client.md # LinkClient 管理
│ ├── authorization.md # 认证管理
│ ├── connection.md # 连接管理
│ ├── data-transfer.md # 数据传输与命令
│ ├── logger.md # 日志配置
│ └── lifecycle.md # 生命周期管理
└── references/ # 参考资料
├── core-classes.md # Agent SDK 核心类
├── link-core-classes.md # Link SDK 核心类
├── link-error-codes.md # Link SDK 错误码
├── troubleshooting.md # 问题排查指南
└── voice-commands.md # 语音指令示例
```
## 常见问题
### Q:Agent 查询无返回结果
**A:** 请检查:
1. Agent SDK 是否使用正确的 API Key 初始化
2. 网络连接是否正常
3. 查询格式是否符合支持的模式(参见 [语音指令](references/voice-commands.md))
### Q:Link SDK 授权失败
**A:** 请确保:
1. 设备上已安装高德 APP
2. 授权配置正确
3. 查看 [Link 错误码](references/link-error-codes.md) 中的错误码说明
### Q:导航数据监听未收到回调
**A:** 请验证:
1. 导航是否已正确启动
2. 数据监听是否在导航启动前注册
3. 定位权限是否已授予
### Q:与高德 APP 的连接频繁断开
**A:** 请检查:
1. AMapLinkManager 是否启用了自动重连
2. 两个应用是否在前台或启用了后台模式
3. 检查连接状态监听的实现
## 相关链接
- [高德开放平台控制台](https://console.amap.com/)
- [Cursor 官方文档](https://docs.cursor.com/)
- [⬆️ 返回首页](../README_zh.md)
FILE:api/agent-query.md
# 智能查询 API
通过 `AMapAgentClientManager` 发起自然语言查询,SDK 会自动解析意图并返回结构化结果。
## 核心类
- **AMapAgentClientManager** — 查询入口(单例)
- **AMapAgentQueryParam** — 查询参数
## 基础查询
```objc
AMapAgentQueryParam *param = [AMapAgentQueryParam new];
param.queryText = @"去西藏";
NSString *sessionId = [[AMapAgentClientManager shareInstance] query:param];
```
`query:` 返回 `sessionId`,用于追踪本次查询会话。结果通过 `setQueryResultCallback:` 异步回调。
## 多轮对话
在上一次查询结果基础上继续对话(如选择搜索结果中的某一个):
```objc
AMapAgentQueryParam *param = [AMapAgentQueryParam new];
param.queryText = @"第一个";
param.selectedObject = previousResult.resultObj; // 上次结果对象
param.lastActionType = previousResult.actionType; // 上次操作类型
NSString *sessionId = [[AMapAgentClientManager shareInstance] query:param];
```
## AMapAgentQueryParam 属性
| 属性 | 类型 | 说明 |
|------|------|------|
| `queryText` | `NSString` | 自然语言查询文本 |
| `lastActionType` | `AMapAgentQueryResultActionType` | 上一次查询的操作类型(多轮对话时设置) |
| `selectedObject` | `id` | 上一次查询的结果对象(多轮对话时设置) |
## 自定义 Agent 服务地址
```objc
// 必须在使用 Agent 前调用
[AMapAgentClientManager configureAgentURL:@"https://your-custom-url.com"];
// 获取当前 URL
NSString *currentURL = [AMapAgentClientManager currentAgentURL];
```
## 相关文档
- [查询结果处理](query-result.md) — 如何处理回调中的 `AMapAgentQueryResult`
- [语音指令参考](../references/voice-commands.md) — 支持的自然语言指令示例
FILE:api/authorization.md
# 认证管理
通过 `AMapAuthorizationManager` 跳转高德地图 APP 完成鉴权授权。
## 前置条件
1. 已在 Info.plist 中配置 URL Scheme 和 `LSApplicationQueriesSchemes`(详见 [quick-start.md](quick-start.md))
2. 已导入头文件:
```objc
#import <MALLMKit/AMapAuthorizationManager.h>
```
## 发起鉴权
通过 `AMapAuthorizationManager` 的 `startAuthenticationWithCallback:` 方法发起授权,SDK 会自动跳转高德地图 APP:
```objc
- (void)openAmap {
__weak typeof(self) weakSelf = self;
[[AMapAuthorizationManager sharedInstance] startAuthenticationWithCallback:^(BOOL success, NSError * _Nonnull error) {
NSLog(@"授权结果: %d, error: %@", success, error);
}];
}
```
### 回调参数说明
| 参数 | 类型 | 说明 |
|------|------|------|
| `success` | BOOL | 授权是否成功 |
| `error` | NSError | 授权失败时的错误信息 |
## 处理授权回调 URL
授权完成后高德 APP 会通过 URL Scheme 回调,需在 App/SceneDelegate 中将 URL 传递给 `AMapAuthorizationManager` 处理:
### AppDelegate 方式
```objc
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options {
[self.viewController handleUrl:url];
return YES;
}
```
### SceneDelegate 方式(iOS 13+)
```objc
- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts {
UIOpenURLContext *context = URLContexts.allObjects.firstObject;
if (context) {
[self.viewController handleUrl:context.URL];
}
}
```
### 业务页面处理 URL
在业务 ViewController 中调用 `AMapAuthorizationManager.handleURL:` 解析授权结果,并在授权成功后持久化状态、发起建联:
```objc
#define kAMapAIPCAuthStatus @"kAMapAIPCAuthStatus"
- (BOOL)handleUrl:(NSURL *)url {
BOOL authResult = [[AMapAuthorizationManager sharedInstance] handleURL:url];
self.isAuthored = authResult;
if (authResult) {
[[NSUserDefaults standardUserDefaults] setBool:authResult forKey:kAMapAIPCAuthStatus];
[self createConnect];
}
return YES;
}
```
## 授权状态持久化
授权成功后通过 `NSUserDefaults` 持久化授权状态,APP 下次启动时可直接尝试建联,无需重复授权:
```objc
// 读取授权状态
self.isAuthored = [[NSUserDefaults standardUserDefaults] boolForKey:kAMapAIPCAuthStatus];
// 已授权则直接建联
if (self.isAuthored) {
[self createConnect];
}
```
## 注意事项
- 授权通过 `AMapAuthorizationManager` 统一管理,无需手动构造 URL
- `handleURL:` 返回 `YES` 表示授权成功,返回 `NO` 表示授权失败
- 建议通过 `NSUserDefaults` 持久化授权状态,避免每次启动都需要重新授权
- 授权成功后应立即调用 `createConnect` 建立 IPC 连接
FILE:api/connection.md
# 连接管理
通过 `AMapLinkManager` 管理与高德 APP 的 IPC 连接。
## 导入头文件
```objc
#import <MALLMKit/AMapLinkManager.h>
#import <MALLMKit/AMapLinkConnectConfig.h>
```
## 初始化与建联
授权成功后,通过 `AMapLinkManager` 单例创建连接:
```objc
- (void)createConnect {
if (!self.isAuthored) {
return;
}
// 防重复连接
if ([[AMapLinkManager sharedInstance] isConnected]) {
return;
}
// 1. 创建连接配置
AMapLinkConnectConfig *config = [AMapLinkConnectConfig new];
config.autoReconnect = YES;
config.maxReconnectAttempts = 50;
config.reconnectDelay = 2;
self.connectConfig = config;
// 2. 初始化并连接
[[AMapLinkManager sharedInstance] initWithConnectConfig:config];
[[AMapLinkManager sharedInstance] connect];
}
```
### AMapLinkConnectConfig 配置参数
| 属性 | 类型 | 说明 |
|------|------|------|
| `autoReconnect` | BOOL | 是否自动重连 |
| `maxReconnectAttempts` | NSUInteger | 最大重连次数 |
| `reconnectDelay` | NSTimeInterval | 重连间隔(秒) |
## 检查连接状态
```objc
BOOL isConnected = [[AMapLinkManager sharedInstance] isConnected];
```
## 监听数据回调
通过 `AMapLinkClientObserverManager` 注册观察者接收高德 APP 回传的消息:
```objc
__weak typeof(self) weakSelf = self;
[[AMapLinkClientObserverManager sharedInstance] addObserver:^(NSString * _Nonnull msg) {
[weakSelf handleReceivedMessage:msg];
}];
```
## 断开连接
```objc
[[AMapLinkManager sharedInstance] disconnect];
```
## 注意事项
- `AMapLinkManager` 是全局单例,通过 `sharedInstance` 获取
- 建联前必须先完成授权(`isAuthored == YES`)
- 建联前应通过 `isConnected` 检查状态,避免重复连接
- 数据回调通过观察者模式接收,UI 更新需切换到主线程
FILE:api/data-transfer.md
# 数据传输与命令
通过 IPC 连接向高德 APP 发送 JSON 命令,实现导航控制、途经点管理、播报设置等功能。
## 发送数据
通过 `AMapLinkManager` 的 `sendDataToClient:` 方法发送 JSON 字符串:
```objc
- (void)sendData:(NSDictionary *)data {
if (!data || ![NSJSONSerialization isValidJSONObject:data]) {
return;
}
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data
options:NSJSONWritingSortedKeys
error:&error];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
if (jsonString) {
[[AMapLinkManager sharedInstance] sendDataToClient:jsonString];
}
}
```
## 接收数据
通过 `AMapLinkClientObserverManager` 注册观察者接收高德 APP 回传的消息:
```objc
__weak typeof(self) weakSelf = self;
[[AMapLinkClientObserverManager sharedInstance] addObserver:^(NSString * _Nonnull msg) {
dispatch_async(dispatch_get_main_queue(), ^{
// 处理接收到的消息
NSLog(@"收到消息: %@", msg);
});
}];
```
## 导航命令参考
所有命令通过 JSON 格式发送,核心字段:
- **`cmd`**:命令类型编号
- **`data`**:命令参数(部分命令无需此字段)
- **`requestId`**:请求标识符
### 添加途经点(cmd: 3)
```objc
NSDictionary *command = @{
@"cmd": @(3),
@"data": @{
@"lon": @116.397455,
@"lat": @39.909187,
@"name": @"天安门",
@"poiid": @"B000A60DA1",
@"entranceList": @[
@{ @"lon": @116.397604, @"lat": @39.907697 }
]
},
@"requestId": @2222223
};
[self sendData:command];
```
### 更改目的地(cmd: 4)
```objc
NSDictionary *command = @{
@"cmd": @(4),
@"data": @{
@"lon": @116.397455,
@"lat": @39.909187,
@"name": @"天安门",
@"poiid": @"B000A60DA1",
@"entranceList": @[
@{ @"lon": @116.397604, @"lat": @39.907697 }
]
},
@"requestId": @2222224
};
[self sendData:command];
```
### 获取导航结构化数据(cmd: 5)
```objc
NSDictionary *command = @{
@"cmd": @(5),
@"requestId": @2222225
};
[self sendData:command];
```
### 更改播报设置(cmd: 6)
```objc
// 骑行播报模式:@"0"-关闭, @"1"-开启
- (void)changeRideBroadcast {
NSArray *rideValues = @[@"0", @"1"];
NSUInteger randomIndex = arc4random_uniform((uint32_t)rideValues.count);
NSString *randomValue = rideValues[randomIndex];
[self sendData:@{
@"cmd": @(6),
@"data": @{
@"value": randomValue,
},
@"requestId": @2222226
}];
}
// 驾车播报模式:0-静音, 1-简洁, 2-详细, 6-极简, 7-智能
- (void)changeCarBroadcast {
NSArray *carValues = @[@(0), @(1), @(2), @(6), @(7)];
NSUInteger randomIndex = arc4random_uniform((uint32_t)carValues.count);
NSNumber *randomValue = carValues[randomIndex];
[self sendData:@{
@"cmd": @(6),
@"data": @{
@"value": randomValue,
},
@"requestId": @2222227
}];
}
```
## 命令速查表
| cmd | 功能 | data 字段 |
|-----|------|-----------|
| 3 | 添加途经点 | lon, lat, name, poiid, entranceList |
| 4 | 更改目的地 | lon, lat, name, poiid, entranceList |
| 5 | 获取导航结构化数据 | 无 |
| 6 | 更改播报设置 | value(驾车: 0/1/2/6/7,骑行: "0"/"1") |
## POI 数据结构
途经点和目的地命令中的 `data` 字段结构:
| 字段 | 类型 | 说明 |
|------|------|------|
| `lon` | NSNumber | 经度 |
| `lat` | NSNumber | 纬度 |
| `name` | NSString | POI 名称 |
| `poiid` | NSString | POI ID |
| `entranceList` | NSArray | 入口坐标列表,每项含 lon/lat |
## 注意事项
- 发送数据前需确保连接已建立(`[[AMapLinkManager sharedInstance] isConnected] == YES`)
- JSON 数据必须通过 `isValidJSONObject:` 校验
- 驾车和骑行的播报 value 类型不同(NSNumber vs NSString)
- 观察者回调可能在子线程,UI 更新需切换到主线程
FILE:api/integrate-agent.md
# 接入 Agent
触发词:**接入agent**
本文档说明如何新建一个 UIViewController 并通过 MALLMKit 接入 Agent SDK(SDK 直连模式)。生成的类名为 `AMapAgentDemoViewController`。
## 整体流程
```
1. 导入头文件 → 2. ViewController 声明 → 3. 初始化 Agent + 导航环境 → 4. 创建导航视图与 UI → 5. 初始化定位 → 6. 发起查询与多轮对话 → 7. 浮动快捷操作 → 8. 日志监听 → 9. 生命周期管理
```
## 1. 导入头文件
```objc
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import "AMapAgentDemoViewController.h"
#import <MALLMKit/AMapAgentClientManager.h>
#import <MALLMKit/AMapAgentQueryParam.h>
#import <MALLMKit/AMapAgentQueryResult.h>
#import <MALLMKit/AMapNaviClientManager.h>
#import <MALLMKit/AMapNaviPbData.h>
#import <MALLMKit/AMapAgentLog.h>
#import <MALLMKit/AMapPOIResult.h>
#import <MALLMKit/AMapNaviEnv.h>
#import <MALLMKit/AMapAgentPOI.h>
#import <MALLMKit/AMapNaviTypeData.h>
#import <AMapNaviKit/AMapNaviDriveDataRepresentable.h>
#import <AMapNaviKit/AMapNaviDriveManager.h>
#import <AMapNaviKit/AMapNaviRoute.h>
#import "UIView+Layout.h"
```
> 如果使用 APP 链路模式,还需导入:
> ```objc
> #import <MALLMKit/AMapLinkManager.h>
> #import <MALLMKit/AMapAuthorizationManager.h>
> #import <MALLMKit/AMapLinkConnectConfig.h>
> ```
## 2. ViewController 声明
### 头文件(.h)
```objc
#import <UIKit/UIKit.h>
#import <AMapNaviKit/AMapNaviKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface AMapAgentDemoViewController : UIViewController
@property (nonatomic, strong) MAMapView *mapView;
@property (nonatomic, strong) id mAMapNaviView;
@end
NS_ASSUME_NONNULL_END
```
### 实现文件(.m)
```objc
static const CGFloat AGENT_BTN_H = 30;
static const CGFloat AGENT_BTN_M = 6;
static const CGFloat AGENT_BTN_PADDING_H = 12;
static const CGFloat AGENT_BTN_PADDING_V = 4;
static const CGFloat AGENT_BTN_RADIUS = 15;
static const CGFloat AGENT_LOG_VIEW_H = 160;
typedef void (^AgentNaviDataCallback)(AMapNaviPbData *navidata);
@interface AMapAgentDemoViewController () <CLLocationManagerDelegate, AMapNaviDriveManagerDelegate, AMapNaviDriveDataRepresentable, AMapNaviDriveViewDelegate, MAMapViewDelegate, AMapAgentLogProtocol>
@property (nonatomic, strong) CLLocationManager *locationManager;
@property (nonatomic, copy) AgentNaviDataCallback naviDataCallback;
@property (nonatomic, strong) AMapPOIResult *currentPoiResult;
@property (nonatomic, copy) NSArray<AMapRoutePOI *> *routePois;
@property (nonatomic, strong) AMapAgentQueryResult *lastQueryResult;
@property (nonatomic, strong) UIButton *mStopNaviButton;
@property (nonatomic, strong) UIButton *mNextActionButton;
@property (nonatomic, strong) UIButton *mYesActionButton;
@property (nonatomic, strong) UITextField *queryTextField;
@property (nonatomic, strong) UIView *inputContainerView;
@property (nonatomic, strong) UITextView *logTextView;
@property (nonatomic, strong) UIView *logContainerView;
@end
```
## 3. 初始化流程(在 init 中调用 initAgent + initNavi)
初始化在 `init` 中完成,确保 Agent 和导航环境在 `viewDidLoad` 之前就绑定好:
```objc
- (instancetype)init {
if (self = [super init]) {
[self initAgent];
[self initNavi];
}
return self;
}
```
### 3.1 initAgent — 设置链路模式、日志、查询回调、重置场景
```objc
- (void)initAgent {
// 设置链路模式为 SDK 直连
[AMapAgentClientManager shareInstance].commandDestination = AMapAgentCommandDestinationSDK;
// 设置日志监听
[[AMapAgentLog shareInstance] setLogDelegate:self];
// 设置查询结果回调
__weak typeof(self) weakSelf = self;
[[AMapAgentClientManager shareInstance] setQueryResultCallback:^(AMapAgentQueryResult * _Nonnull queryResult) {
__strong typeof(weakSelf) strongSelf = weakSelf;
NSString *logMsg = [NSString stringWithFormat:@"summary: %@, actionType: %ld, stateType: %ld, seq: %ld",
queryResult.summary, (long)queryResult.actionType,
(long)queryResult.stateType, (long)queryResult.sequence];
NSLog(@"onQueryResult %@, sessionID: %@", logMsg, queryResult.sessionId);
[strongSelf appendLogMessage:logMsg];
if (queryResult.resultObj) {
if (queryResult.actionType == AMapAgentQueryResultActionTypeSearchPoi) {
// POI 搜索结果
strongSelf.currentPoiResult = queryResult.resultObj;
} else if (queryResult.actionType == AMapAgentQueryResultActionTypeRouteSearch) {
// 顺路搜结果
strongSelf.routePois = queryResult.resultObj;
} else if (queryResult.actionType == AMapAgentQueryResultActionTypeRequestRoute) {
// 路线规划完成,自动开始驾车模拟导航
[[AMapNaviDriveManager sharedInstance] setIsUseInternalTTS:YES];
[[AMapNaviDriveManager sharedInstance] selectNaviRouteWithRouteID:0];
[[AMapNaviDriveManager sharedInstance] setEmulatorNaviSpeed:120];
[[AMapNaviDriveManager sharedInstance] startEmulatorNavi];
}
}
strongSelf.lastQueryResult = queryResult;
}];
// 重置场景到主图
[[AMapAgentClientManager shareInstance] resetAgentScene:@"home"];
}
```
### 3.2 initNavi — 配置导航环境、家/公司位置、车辆信息、导航数据监听
```objc
- (void)initNavi {
AMapNaviEnv *env = [AMapNaviEnv new];
AMapAgentPOI *homeLocation = [AMapAgentPOI new];
env.homeLocation = homeLocation;
AMapAgentPOI *workLocation = [AMapAgentPOI new];
env.workLocation = workLocation;
env.homeLocation.name = @"望京西园一区";
env.homeLocation.coordinate = CLLocationCoordinate2DMake(40.004585, 116.476334);
env.homeLocation.uid = @"B000A7QPDF";
env.workLocation.name = @"阿里中心·望京B座";
env.workLocation.coordinate = CLLocationCoordinate2DMake(40.002577, 116.489854);
env.workLocation.uid = @"B0FFHU7UFS";
AMapNaviVehicleInfo *carInfo = [AMapNaviVehicleInfo new];
env.amapVehicleInfo = carInfo;
env.amapVehicleInfo.vehicleId = @"京DFZ588";
env.amapNaviType = AMapNaviTypeDrive;
env.multipleRoute = YES;
env.avoidCongestion = NO;
env.avoidHighway = NO;
env.avoidCost = NO;
env.prioritiseHighway = NO;
[AMapNaviClientManager shareInstance].amapNaviEnv = env;
[AMapNaviClientManager shareInstance].locationUpdateInterval = 1.0;
// 导航数据监听
self.naviDataCallback = ^(AMapNaviPbData * _Nonnull navidata) {
};
[[AMapNaviClientManager shareInstance] addNaviDataListener:self.naviDataCallback];
}
```
> **初始化顺序要求**:`AMapAgentClientManager` 和 `AMapNaviClientManager` 必须在 `AMapLinkManager` 之前初始化。
## 4. 创建导航视图与 UI(在 viewDidLoad 中)
`viewDidLoad` 中依次创建:导航视图 → 底部输入区域 → 日志面板 → 浮动操作按钮 → 初始化定位。
```objc
- (void)viewDidLoad {
[super viewDidLoad];
// 1. 创建导航视图(全屏)
self.mAMapNaviView = [[AMapNaviDriveView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
[[AMapNaviClientManager shareInstance] setAmapNaviView:self.mAMapNaviView];
[(AMapNaviDriveView *)self.mAMapNaviView setDelegate:self];
[self.view addSubview:self.mAMapNaviView];
[[AMapNaviDriveManager sharedInstance] addDataRepresentative:self.mAMapNaviView];
// 2. 底部输入区域(输入框 + 发送查询 / 重置对话按钮)
CGFloat inputAreaHeight = 110;
CGFloat inputAreaY = self.view.height - inputAreaHeight;
self.inputContainerView = [[UIView alloc] initWithFrame:CGRectMake(0, inputAreaY, self.view.width, inputAreaHeight)];
self.inputContainerView.backgroundColor = [UIColor whiteColor];
self.inputContainerView.layer.shadowColor = [UIColor blackColor].CGColor;
self.inputContainerView.layer.shadowOffset = CGSizeMake(0, -2);
self.inputContainerView.layer.shadowOpacity = 0.15;
self.inputContainerView.layer.shadowRadius = 4;
[self.view addSubview:self.inputContainerView];
CGFloat horizontalPadding = 16;
// 输入框(橙色边框)
self.queryTextField = [[UITextField alloc] initWithFrame:CGRectMake(horizontalPadding, 10, self.view.width - horizontalPadding * 2, 44)];
self.queryTextField.placeholder = @"输入查询词,如:导航去天安门。";
self.queryTextField.font = [UIFont systemFontOfSize:16];
self.queryTextField.borderStyle = UITextBorderStyleNone;
self.queryTextField.layer.borderColor = [UIColor orangeColor].CGColor;
self.queryTextField.layer.borderWidth = 2.0;
self.queryTextField.layer.cornerRadius = 4;
self.queryTextField.leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 12, 44)];
self.queryTextField.leftViewMode = UITextFieldViewModeAlways;
self.queryTextField.rightView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 12, 44)];
self.queryTextField.rightViewMode = UITextFieldViewModeAlways;
self.queryTextField.returnKeyType = UIReturnKeySend;
[self.queryTextField addTarget:self action:@selector(sendQueryAction) forControlEvents:UIControlEventEditingDidEndOnExit];
[self.inputContainerView addSubview:self.queryTextField];
// "发送查询" 和 "重置对话" 按钮
CGFloat btnWidth = (self.view.width - horizontalPadding * 2 - 12) / 2.0;
CGFloat btnHeight = 44;
CGFloat btnY = 10 + 44 + 8;
UIButton *sendButton = [UIButton buttonWithType:UIButtonTypeSystem];
sendButton.frame = CGRectMake(horizontalPadding, btnY, btnWidth, btnHeight);
[sendButton setTitle:@"发送查询" forState:UIControlStateNormal];
sendButton.titleLabel.font = [UIFont boldSystemFontOfSize:16];
sendButton.backgroundColor = [UIColor whiteColor];
[sendButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
sendButton.layer.borderColor = [UIColor lightGrayColor].CGColor;
sendButton.layer.borderWidth = 1.0;
sendButton.layer.cornerRadius = 4;
[sendButton addTarget:self action:@selector(sendQueryAction) forControlEvents:UIControlEventTouchUpInside];
[self.inputContainerView addSubview:sendButton];
UIButton *resetButton = [UIButton buttonWithType:UIButtonTypeSystem];
resetButton.frame = CGRectMake(horizontalPadding + btnWidth + 12, btnY, btnWidth, btnHeight);
[resetButton setTitle:@"重置对话" forState:UIControlStateNormal];
resetButton.titleLabel.font = [UIFont boldSystemFontOfSize:16];
resetButton.backgroundColor = [UIColor whiteColor];
[resetButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
resetButton.layer.borderColor = [UIColor lightGrayColor].CGColor;
resetButton.layer.borderWidth = 1.0;
resetButton.layer.cornerRadius = 4;
[resetButton addTarget:self action:@selector(resetConversationAction) forControlEvents:UIControlEventTouchUpInside];
[self.inputContainerView addSubview:resetButton];
// 3. Agent 回调日志面板(在输入区域上方)
CGFloat logPanelHeight = AGENT_LOG_VIEW_H;
CGFloat logTop = inputAreaY - logPanelHeight;
self.logContainerView = [[UIView alloc] initWithFrame:CGRectMake(0, logTop, self.view.width, logPanelHeight)];
self.logContainerView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.7];
[self.view addSubview:self.logContainerView];
UILabel *logTitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(12, 4, 200, 20)];
logTitleLabel.text = @"📋 Agent 回调日志";
logTitleLabel.textColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8];
logTitleLabel.font = [UIFont boldSystemFontOfSize:12];
[self.logContainerView addSubview:logTitleLabel];
self.logTextView = [[UITextView alloc] initWithFrame:CGRectMake(8, 24, self.view.width - 16, logPanelHeight - 28)];
self.logTextView.backgroundColor = [UIColor clearColor];
self.logTextView.textColor = [UIColor greenColor];
self.logTextView.font = [UIFont fontWithName:@"Menlo" size:11];
self.logTextView.editable = NO;
self.logTextView.scrollEnabled = YES;
self.logTextView.showsVerticalScrollIndicator = YES;
self.logTextView.textContainer.lineBreakMode = NSLineBreakByWordWrapping;
self.logTextView.textContainer.maximumNumberOfLines = 0;
self.logTextView.textContainerInset = UIEdgeInsetsMake(4, 0, 4, 0);
self.logTextView.text = @"等待 Agent 回调...\n";
[self.logContainerView addSubview:self.logTextView];
// 4. 浮动操作按钮(日志面板上方:去第一个、是的、停止导航)
CGFloat floatingY = self.logContainerView.top - AGENT_BTN_H - 12;
CGFloat floatingX = self.view.width - AGENT_BTN_M;
self.mStopNaviButton = [self createOutlineButton:@"⏹ 停止导航" action:@selector(testStopNavi) color:[UIColor systemRedColor]];
[self.mStopNaviButton sizeToFit];
self.mStopNaviButton.frame = CGRectMake(floatingX - self.mStopNaviButton.width, floatingY, self.mStopNaviButton.width, AGENT_BTN_H);
[self.view addSubview:self.mStopNaviButton];
floatingX = self.mStopNaviButton.left - AGENT_BTN_M;
self.mYesActionButton = [self createOutlineButton:@"✅ 是的" action:@selector(testSelectYes) color:[UIColor systemGreenColor]];
[self.mYesActionButton sizeToFit];
self.mYesActionButton.frame = CGRectMake(floatingX - self.mYesActionButton.width, floatingY, self.mYesActionButton.width, AGENT_BTN_H);
[self.view addSubview:self.mYesActionButton];
floatingX = self.mYesActionButton.left - AGENT_BTN_M;
self.mNextActionButton = [self createOutlineButton:@"👉 去第一个" action:@selector(testSelectFirst) color:[UIColor systemPurpleColor]];
[self.mNextActionButton sizeToFit];
self.mNextActionButton.frame = CGRectMake(floatingX - self.mNextActionButton.width, floatingY, self.mNextActionButton.width, AGENT_BTN_H);
[self.view addSubview:self.mNextActionButton];
// 5. 初始化定位
[self initLocation];
}
```
### UI 辅助方法
```objc
- (UIButton *)createOutlineButton:(NSString *)title action:(SEL)action color:(UIColor *)color {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setTitle:title forState:UIControlStateNormal];
[button setTitleColor:color forState:UIControlStateNormal];
button.titleLabel.font = [UIFont systemFontOfSize:13 weight:UIFontWeightSemibold];
button.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.9];
button.layer.cornerRadius = AGENT_BTN_RADIUS;
button.layer.masksToBounds = YES;
button.layer.borderWidth = 1.5;
button.layer.borderColor = color.CGColor;
button.contentEdgeInsets = UIEdgeInsetsMake(AGENT_BTN_PADDING_V, AGENT_BTN_PADDING_H, AGENT_BTN_PADDING_V, AGENT_BTN_PADDING_H);
[button addTarget:self action:action forControlEvents:UIControlEventTouchUpInside];
return button;
}
- (void)appendLogMessage:(NSString *)message {
dispatch_async(dispatch_get_main_queue(), ^{
NSString *timestamp = [NSDateFormatter localizedStringFromDate:[NSDate date]
dateStyle:NSDateFormatterNoStyle
timeStyle:NSDateFormatterMediumStyle];
NSString *logLine = [NSString stringWithFormat:@"[%@] %@\n", timestamp, message];
self.logTextView.text = [self.logTextView.text stringByAppendingString:logLine];
NSRange bottom = NSMakeRange(self.logTextView.text.length - 1, 1);
[self.logTextView scrollRangeToVisible:bottom];
});
}
```
## 5. 定位管理
```objc
- (void)initLocation {
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self startLocationServices];
}
- (void)startLocationServices {
[self.locationManager startUpdatingLocation];
}
- (void)locationManagerDidChangeAuthorization:(CLLocationManager *)manager {
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
if (status == kCLAuthorizationStatusNotDetermined) {
[manager requestWhenInUseAuthorization];
} else if (status == kCLAuthorizationStatusAuthorizedWhenInUse ||
status == kCLAuthorizationStatusAuthorizedAlways) {
[manager startUpdatingLocation];
} else {
NSLog(@"定位权限未授予");
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
CLLocation *location = [locations lastObject];
[[AMapNaviClientManager shareInstance] updateMyLocation:location];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(@"定位失败: %@", error.localizedDescription);
}
```
## 6. 发起查询与多轮对话
### 基础查询方法
```objc
- (NSString *)query:(AMapAgentQueryParam *)param {
NSString *sessionId = [[AMapAgentClientManager shareInstance] query:param];
return sessionId;
}
```
### 输入框发送查询(自动携带多轮上下文)
用户在输入框中输入自然语言查询词,点击"发送查询"或按回车键发送。自动携带上一次的搜索结果上下文,实现多轮对话:
```objc
- (void)sendQueryAction {
NSString *queryText = self.queryTextField.text;
if (queryText.length == 0) {
return;
}
AMapAgentQueryParam *param = [AMapAgentQueryParam new];
param.queryText = queryText;
// 多轮对话:自动携带上一次的搜索结果上下文
if (self.currentPoiResult) {
param.selectedObject = self.currentPoiResult;
param.lastActionType = AMapAgentQueryResultActionTypeSearchPoi;
} else if (self.routePois) {
param.selectedObject = self.routePois;
param.lastActionType = AMapAgentQueryResultActionTypeRouteSearch;
}
[self query:param];
self.queryTextField.text = @"";
[self.queryTextField resignFirstResponder];
}
```
### 重置对话
清除所有多轮上下文,重置场景到主图:
```objc
- (void)resetConversationAction {
self.currentPoiResult = nil;
self.routePois = nil;
self.lastQueryResult = nil;
self.logTextView.text = @"";
self.queryTextField.text = @"";
[[AMapAgentClientManager shareInstance] resetAgentScene:@"home"];
[self appendLogMessage:@"对话已重置,场景切换到主图"];
}
```
## 7. 浮动快捷操作
三个浮动按钮用于常见的多轮交互快捷操作:
```objc
// 选择搜索结果中的第一个
- (void)testSelectFirst {
AMapAgentQueryParam *param = [AMapAgentQueryParam new];
param.queryText = @"第一个";
if (self.currentPoiResult) {
param.selectedObject = self.currentPoiResult;
param.lastActionType = AMapAgentQueryResultActionTypeSearchPoi;
} else if (self.routePois) {
param.selectedObject = self.routePois;
param.lastActionType = AMapAgentQueryResultActionTypeRouteSearch;
}
[self query:param];
}
// 确认选择
- (void)testSelectYes {
AMapAgentQueryParam *param = [AMapAgentQueryParam new];
param.queryText = @"是的,确认";
if (self.currentPoiResult) {
param.selectedObject = self.currentPoiResult;
param.lastActionType = AMapAgentQueryResultActionTypeSearchPoi;
}
[self query:param];
}
// 停止导航
- (void)testStopNavi {
AMapAgentQueryParam *param = [AMapAgentQueryParam new];
param.queryText = @"结束导航";
[self query:param];
}
```
## 8. 场景管理
查询前需确保场景正确,影响 Agent 对意图的理解:
```objc
// 行前主图场景
[[AMapAgentClientManager shareInstance] resetAgentScene:@"home"];
// 路线规划场景(算路成功后切换)
[[AMapAgentClientManager shareInstance] resetAgentScene:@"route"];
// 行中导航场景(开始导航后切换)
[[AMapAgentClientManager shareInstance] resetAgentScene:@"navi"];
// 搜索场景
[[AMapAgentClientManager shareInstance] resetAgentScene:@"search"];
```
## 9. 日志监听(AMapAgentLogProtocol)
```objc
- (void)onLog:(AMapAgentLogLevel)logLevel logContent:(NSString *)logContent {
NSLog(@"logLevel: %lu, message: %@", logLevel, logContent);
}
```
## 10. 生命周期管理
```objc
- (void)viewDidDisappear:(BOOL)animated {
[AMapAgentClientManager destroy];
[AMapNaviClientManager destroy];
[self.locationManager stopUpdatingLocation];
}
```
> **注意**:`AMapAgentClientManager` 和 `AMapNaviClientManager` 是全局单例,通常不需要在页面销毁时调用 `destroy`。仅在确定不再使用 SDK 时才调用。
## 11. 错误码参考
| 错误码 | 常量 | 说明 |
|--------|------|------|
| -20001 | `AMapAgentQueryResultErrorCodeCmdNotSupport` | 当前命令不支持 |
| -20002 | `AMapAgentQueryResultErrorCodeQueryTimeout` | query 超时 |
| -20003 | `AMapAgentQueryResultErrorCodeHomeNotSet` | 家位置未设置 |
| -20004 | `AMapAgentQueryResultErrorCodeCompanyNotSet` | 公司位置未设置 |
| -20005 | `AMapAgentQueryResultErrorCodeCmdTimeout` | 命令执行超时 |
| -20006 | `AMapAgentQueryResultErrorCodeViaNotFound` | 未找到途经点 |
| -20007 | `AMapAgentQueryResultErrorCodeDoAction` | doaction 参数错误 |
| -20008 | `AMapAgentQueryResultErrorCodeRequestRoute` | requestRoute 参数错误 |
FILE:api/lifecycle.md
# 生命周期管理
管理 Agent 场景状态、会话重置和单例销毁。
## 场景管理
通过 `resetAgentScene:` 切换 Agent 当前所处的业务场景:
```objc
// 场景值说明:
// "home" — 行前场景(主图)
// "route" — 行前场景(路线规划)
// "navi" — 行中场景(导航中)
// "search" — 搜索场景
[[AMapAgentClientManager shareInstance] resetAgentScene:@"home"];
```
> 切换场景会影响 Agent 对自然语言的理解上下文。例如在 `"navi"` 场景下,"加个途经点" 才会被正确识别。
## 会话状态重置
清除当前多轮对话上下文,开始新的会话:
```objc
[[AMapAgentClientManager shareInstance] resetAgentStatus];
```
## 单例销毁
在不再需要 SDK 时(如退出地图模块),按顺序销毁:
```objc
// 1. 移除所有监听器
[[AMapNaviClientManager shareInstance] removeNaviDataListener:self.naviDataCallback];
// 2. 销毁单例(按依赖顺序)
[AMapAgentClientManager destroy];
[AMapNaviClientManager destroy];
[AMapLinkManager destroy]; // 仅 APP 链路模式需要
```
> `destroy` 返回 `NO` 表示单例仍被外部强引用,请检查是否有未释放的引用。
## 导航 Manager 销毁通知
当外部控制销毁导航 Manager 时,需通知 Agent 清理内部数据:
```objc
[[AMapNaviClientManager shareInstance] onNaviManagerDestroyed:AMapNaviTypeDrive];
```
FILE:api/link-client.md
# IPC 链路管理
APP 链路模式下,通过 `AMapLinkManager` 与高德 APP 建立 IPC 连接,通过 `AMapAuthorizationManager` 完成授权。
> 仅当 `commandDestination = AMapAgentCommandDestinationAPP` 时需要使用。SDK 链路模式可跳过本文档。
## 建联配置
```objc
AMapLinkConnectConfig *config = [AMapLinkConnectConfig defaultConfig];
config.autoReconnect = YES; // 是否自动重连,默认 NO
config.maxReconnectAttempts = 5; // 最大重连次数,默认 5
config.reconnectDelay = 2.0; // 重连间隔(秒),默认 2
[[AMapLinkManager sharedInstance] initWithConnectConfig:config];
[[AMapLinkManager sharedInstance] connect];
```
## 连接状态监听
```objc
NSString *observerID = [[AMapLinkManager sharedInstance] addReachablityChanged:^(BOOL isReachable) {
NSLog(@"连接状态: %@", isReachable ? @"已连接" : @"已断开");
}];
// 移除监听
[[AMapLinkManager sharedInstance] removeReachablityObserver:observerID];
```
## 错误监听
```objc
NSString *errorObserverID = [[AMapLinkManager sharedInstance] addErrorOccurred:^(NSError *error) {
NSLog(@"连接错误: %@", error.localizedDescription);
}];
[[AMapLinkManager sharedInstance] removeErrorObserver:errorObserverID];
```
## Server 探测
```objc
[[AMapLinkManager sharedInstance] startServerProbing]; // 手动开始探测
[[AMapLinkManager sharedInstance] stopServerProbing]; // 停止探测
BOOL isProbing = [[AMapLinkManager sharedInstance] isServerProbing];
```
## APP 授权
```objc
// 1. 检查高德 APP 是否安装
if (![[AMapAuthorizationManager sharedInstance] isInstallAMapApp]) {
[[AMapAuthorizationManager sharedInstance] turnToAppStore];
return;
}
// 2. 发起授权
[[AMapAuthorizationManager sharedInstance] startAuthenticationWithCallback:^(BOOL success, NSError *error) {
if (success) {
NSLog(@"授权成功");
}
}];
// 3. 在 AppDelegate 中处理回调
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options {
return [[AMapAuthorizationManager sharedInstance] handleURL:url];
}
```
## Info.plist 配置
APP 链路需要在 `Info.plist` 中声明:
```xml
<key>LSApplicationQueriesSchemes</key>
<array>
<string>amapuri</string>
</array>
```
## 授权错误码
| 错误码 | 含义 |
|--------|------|
| `AppAuthSuccess` | 授权成功 |
| `InvalidAPIKey` | 无效的 apiKey |
| `MissingAPIKey` | 缺少 apiKey |
| `NetworkFailed` | 校验网络异常 |
| `AppNotInstalled` | 高德 APP 未安装 |
| `AppOpenFailed` | 跳转 APP 失败 |
| `AppAuthFailed` | 授权失败 |
FILE:api/link-quick-start.md
# 链接高德 APP
触发词:**链接高德app**
本文档说明如何新建一个 UIViewController 并通过 MALLMKit 接入 Link SDK,实现与高德地图 APP 的 IPC 通信(授权认证、建联、收发数据)。生成的类名为 `AMapLinkDemoViewController`,同时生成配套的 `AMapLinkDemoNavBarView`(导航栏,高德蓝渐变背景 + 返回按钮)和 `AMapLinkDemoEventActionView`(操作按钮面板,分组配色 + 卡片式布局)。
## 整体流程
```
1. 创建 AMapLinkDemoNavBarView → 2. 创建 AMapLinkDemoEventActionView → 3. 创建 AMapLinkDemoViewController → 4. 配置 Info.plist → 5. 处理授权回调 URL
```
## 1. 创建 AMapLinkDemoNavBarView(导航栏视图)
### 头文件(AMapLinkDemoNavBarView.h)
```objc
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface AMapLinkDemoNavBarView : UIView
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIButton *backButton;
@property (nonatomic, copy, nullable) void (^onBackTapped)(void);
- (instancetype)initWithFrame:(CGRect)frame;
- (void)setTitle:(NSString *)title;
@end
NS_ASSUME_NONNULL_END
```
### 实现文件(AMapLinkDemoNavBarView.m)
```objc
#import "AMapLinkDemoNavBarView.h"
@implementation AMapLinkDemoNavBarView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// 高德蓝渐变背景
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = CGRectMake(0, 0, frame.size.width, frame.size.height);
gradient.colors = @[
(__bridge id)[UIColor colorWithRed:0.0 green:0.48 blue:1.0 alpha:1.0].CGColor,
(__bridge id)[UIColor colorWithRed:0.0 green:0.36 blue:0.85 alpha:1.0].CGColor
];
gradient.startPoint = CGPointMake(0, 0);
gradient.endPoint = CGPointMake(1, 1);
[self.layer insertSublayer:gradient atIndex:0];
// 返回按钮
_backButton = [UIButton buttonWithType:UIButtonTypeSystem];
[_backButton setTitle:@"‹ 返回" forState:UIControlStateNormal];
[_backButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
_backButton.titleLabel.font = [UIFont systemFontOfSize:16.0 weight:UIFontWeightMedium];
[_backButton addTarget:self action:@selector(backButtonTapped) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:_backButton];
// 标题
_titleLabel = [[UILabel alloc] init];
_titleLabel.textAlignment = NSTextAlignmentCenter;
_titleLabel.font = [UIFont boldSystemFontOfSize:18.0];
_titleLabel.textColor = [UIColor whiteColor];
[self addSubview:_titleLabel];
// 底部阴影线
self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowOffset = CGSizeMake(0, 2);
self.layer.shadowOpacity = 0.1;
self.layer.shadowRadius = 4;
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
CGFloat statusBarHeight = 20;
if (@available(iOS 11.0, *)) {
UIWindow *window = UIApplication.sharedApplication.windows.firstObject;
statusBarHeight = window.safeAreaInsets.top;
}
CGFloat titleHeight = 44;
CGFloat titleWidth = self.bounds.size.width - 160;
_titleLabel.frame = CGRectMake((self.bounds.size.width - titleWidth) / 2, statusBarHeight, titleWidth, titleHeight);
_backButton.frame = CGRectMake(8, statusBarHeight, 70, titleHeight);
// 更新渐变 layer 尺寸
CAGradientLayer *gradient = (CAGradientLayer *)self.layer.sublayers.firstObject;
if ([gradient isKindOfClass:[CAGradientLayer class]]) {
gradient.frame = self.bounds;
}
}
- (void)backButtonTapped {
if (self.onBackTapped) {
self.onBackTapped();
}
}
- (void)setTitle:(NSString *)title {
self.titleLabel.text = title;
}
@end
```
## 2. 创建 AMapLinkDemoEventActionView(操作按钮面板)
### 头文件(AMapLinkDemoEventActionView.h)
```objc
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@protocol AMapLinkDemoEventActionViewDelegate <NSObject>
- (void)openAmap;
- (void)createConnect;
- (void)disconnect;
- (void)sendData;
- (void)startNavi;
- (void)changeRideBroadcast;
- (void)changeCarBroadcast;
- (void)changeDestination;
- (void)addViaPoint;
- (void)copyLog;
- (void)clearLog;
@end
@interface AMapLinkDemoEventActionView : UIView
@property (nonatomic, weak) id<AMapLinkDemoEventActionViewDelegate> delegate;
- (instancetype)initWithOriginX:(CGFloat)x originY:(CGFloat)y width:(CGFloat)width;
- (void)updateInfo:(NSDictionary *)dict;
@end
NS_ASSUME_NONNULL_END
```
### 实现文件(AMapLinkDemoEventActionView.m)
```objc
#import "AMapLinkDemoEventActionView.h"
@interface AMapLinkDemoEventActionView ()
@property (nonatomic, strong) NSArray *btnDataList;
@property (nonatomic, strong) NSMutableArray *btnViewList;
@end
typedef NS_ENUM(NSUInteger, AMapLinkDemoBtnType) {
AMapLinkDemoBtnType_openAmap = 1,
AMapLinkDemoBtnType_createConnect,
AMapLinkDemoBtnType_sendData,
AMapLinkDemoBtnType_disconnect,
AMapLinkDemoBtnType_startNavi,
AMapLinkDemoBtnType_changeRideBroadcast,
AMapLinkDemoBtnType_changeCarBroadcast,
AMapLinkDemoBtnType_changeDestination,
AMapLinkDemoBtnType_addViaPoint,
AMapLinkDemoBtnType_copyLog,
AMapLinkDemoBtnType_clearLog
};
@implementation AMapLinkDemoEventActionView
- (instancetype)initWithOriginX:(CGFloat)x originY:(CGFloat)y width:(CGFloat)width {
CGFloat height = [self calculateRequiredHeight:width];
CGRect frame = CGRectMake(x, y, width, height);
return [self initWithFrame:frame];
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_btnViewList = [NSMutableArray array];
[self initUI];
[self updateInfo:@{}];
}
return self;
}
- (void)updateInfo:(NSDictionary *)dict {
BOOL isConnected = [[dict valueForKey:@"isConnected"] boolValue];
BOOL isAuthored = [[dict valueForKey:@"isAuthored"] integerValue];
UIColor *amapBlue = [UIColor colorWithRed:0.0 green:0.48 blue:1.0 alpha:1.0];
UIColor *successGreen = [UIColor colorWithRed:0.2 green:0.78 blue:0.35 alpha:1.0];
for (UIButton *button in self.btnViewList) {
NSInteger index = button.tag;
NSDictionary *btnInfo = self.btnDataList[index];
AMapLinkDemoBtnType btnType = [btnInfo[@"btnType"] integerValue];
if (btnType == AMapLinkDemoBtnType_openAmap) {
if (isAuthored) {
[button setEnabled:NO];
[button setTitle:@"✓ 已鉴权" forState:UIControlStateDisabled];
button.backgroundColor = [successGreen colorWithAlphaComponent:0.15];
[button setTitleColor:successGreen forState:UIControlStateDisabled];
button.layer.borderColor = successGreen.CGColor;
} else {
[button setEnabled:YES];
[button setTitle:@"鉴权验证" forState:UIControlStateNormal];
button.backgroundColor = amapBlue;
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
button.layer.borderColor = amapBlue.CGColor;
}
} else if (btnType == AMapLinkDemoBtnType_createConnect) {
if (isConnected && isAuthored) {
[button setEnabled:NO];
[button setTitle:@"✓ 已连接" forState:UIControlStateDisabled];
button.backgroundColor = [successGreen colorWithAlphaComponent:0.15];
[button setTitleColor:successGreen forState:UIControlStateDisabled];
button.layer.borderColor = successGreen.CGColor;
} else {
[button setTitle:@"创建连接" forState:UIControlStateNormal];
[button setEnabled:isAuthored ? YES : NO];
if (isAuthored) {
button.backgroundColor = amapBlue;
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
button.layer.borderColor = amapBlue.CGColor;
} else {
button.backgroundColor = [UIColor colorWithRed:0.95 green:0.95 blue:0.95 alpha:1.0];
[button setTitleColor:[UIColor colorWithRed:0.7 green:0.7 blue:0.7 alpha:1.0] forState:UIControlStateDisabled];
button.layer.borderColor = [UIColor colorWithRed:0.88 green:0.88 blue:0.88 alpha:1.0].CGColor;
}
}
} else if (btnType == AMapLinkDemoBtnType_copyLog || btnType == AMapLinkDemoBtnType_clearLog) {
// 日志操作按钮始终可用
[button setEnabled:YES];
button.backgroundColor = [UIColor colorWithRed:0.96 green:0.96 blue:0.97 alpha:1.0];
[button setTitleColor:[UIColor colorWithRed:0.4 green:0.4 blue:0.45 alpha:1.0] forState:UIControlStateNormal];
button.layer.borderColor = [UIColor colorWithRed:0.88 green:0.88 blue:0.88 alpha:1.0].CGColor;
} else {
if (isConnected && isAuthored) {
[button setEnabled:YES];
button.backgroundColor = [UIColor whiteColor];
[button setTitleColor:[UIColor colorWithRed:0.2 green:0.2 blue:0.25 alpha:1.0] forState:UIControlStateNormal];
button.layer.borderColor = [UIColor colorWithRed:0.82 green:0.82 blue:0.85 alpha:1.0].CGColor;
} else {
[button setEnabled:NO];
button.backgroundColor = [UIColor colorWithRed:0.95 green:0.95 blue:0.95 alpha:1.0];
[button setTitleColor:[UIColor colorWithRed:0.7 green:0.7 blue:0.7 alpha:1.0] forState:UIControlStateDisabled];
button.layer.borderColor = [UIColor colorWithRed:0.88 green:0.88 blue:0.88 alpha:1.0].CGColor;
}
}
}
}
- (void)handleButtonClick:(UIButton *)sender {
NSInteger index = sender.tag;
if (index >= 0 && index < self.btnDataList.count) {
NSDictionary *btnInfo = self.btnDataList[index];
SEL action = NSSelectorFromString(btnInfo[@"action"]);
if (action && [self.delegate respondsToSelector:action]) {
[self.delegate performSelector:action];
}
}
}
- (NSArray *)btnDataList {
return @[
@{ @"title": @"鉴权验证", @"action": @"openAmap", @"btnType": @(AMapLinkDemoBtnType_openAmap) },
@{ @"title": @"创建连接", @"action": @"createConnect", @"btnType": @(AMapLinkDemoBtnType_createConnect) },
@{ @"title": @"测试联通性", @"action": @"sendData", @"btnType": @(AMapLinkDemoBtnType_sendData) },
@{ @"title": @"断开链接", @"action": @"disconnect", @"btnType": @(AMapLinkDemoBtnType_disconnect) },
@{ @"title": @"获取导航结构化数据", @"action": @"startNavi", @"btnType": @(AMapLinkDemoBtnType_startNavi) },
@{ @"title": @"播报-ride", @"action": @"changeRideBroadcast", @"btnType": @(AMapLinkDemoBtnType_changeRideBroadcast) },
@{ @"title": @"播报-car", @"action": @"changeCarBroadcast", @"btnType": @(AMapLinkDemoBtnType_changeCarBroadcast) },
@{ @"title": @"更改目的地", @"action": @"changeDestination", @"btnType": @(AMapLinkDemoBtnType_changeDestination) },
@{ @"title": @"添加途经点", @"action": @"addViaPoint", @"btnType": @(AMapLinkDemoBtnType_addViaPoint) },
@{ @"title": @"复制", @"action": @"copyLog", @"btnType": @(AMapLinkDemoBtnType_copyLog) },
@{ @"title": @"清空日志", @"action": @"clearLog", @"btnType": @(AMapLinkDemoBtnType_clearLog) }
];
}
- (CGFloat)calculateRequiredHeight:(CGFloat)width {
CGFloat buttonWidth = 100.0;
CGFloat buttonHeight = 32.0;
CGFloat horizontalMargin = 10.0;
CGFloat verticalMargin = 8.0;
int buttonsPerRow = floor((width + horizontalMargin) / (buttonWidth + horizontalMargin));
if (buttonsPerRow < 1) buttonsPerRow = 1;
int numRows = ceil((float)self.btnDataList.count / buttonsPerRow);
return verticalMargin + numRows * (buttonHeight + verticalMargin) + verticalMargin;
}
- (void)initUI {
CGFloat containerHeight = self.frame.size.height;
UIView *buttonContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, containerHeight)];
buttonContainer.backgroundColor = [UIColor clearColor];
[self addSubview:buttonContainer];
NSMutableArray *buttons = [NSMutableArray array];
for (int i = 0; i < self.btnDataList.count; i++) {
NSDictionary *btnInfo = self.btnDataList[i];
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
[button setTitle:btnInfo[@"title"] forState:UIControlStateNormal];
button.tag = i;
[button addTarget:self action:@selector(handleButtonClick:) forControlEvents:UIControlEventTouchUpInside];
// 统一字体和多行支持
button.titleLabel.font = [UIFont systemFontOfSize:13.0 weight:UIFontWeightMedium];
button.titleLabel.numberOfLines = 2;
button.titleLabel.textAlignment = NSTextAlignmentCenter;
button.titleLabel.adjustsFontSizeToFitWidth = YES;
button.titleLabel.minimumScaleFactor = 0.8;
// 现代化圆角 + 边框 + 阴影
button.backgroundColor = [UIColor whiteColor];
button.layer.cornerRadius = 8.0;
button.layer.borderWidth = 1.0;
button.layer.borderColor = [UIColor colorWithRed:0.88 green:0.88 blue:0.88 alpha:1.0].CGColor;
button.layer.shadowColor = [UIColor blackColor].CGColor;
button.layer.shadowOffset = CGSizeMake(0, 1);
button.layer.shadowOpacity = 0.06;
button.layer.shadowRadius = 3;
button.clipsToBounds = NO;
[button setTitleColor:[UIColor colorWithRed:0.2 green:0.2 blue:0.25 alpha:1.0] forState:UIControlStateNormal];
[buttons addObject:button];
[buttonContainer addSubview:button];
[self.btnViewList addObject:button];
}
[self layoutButtonsInContainer:buttonContainer withButtons:buttons];
}
- (void)layoutButtonsInContainer:(UIView *)container withButtons:(NSArray *)buttons {
if (buttons.count == 0) return;
CGFloat buttonWidth = 100.0;
CGFloat buttonHeight = 32.0;
CGFloat horizontalMargin = 10.0;
CGFloat verticalMargin = 8.0;
CGFloat containerWidth = container.frame.size.width;
int buttonsPerRow = floor((containerWidth + horizontalMargin) / (buttonWidth + horizontalMargin));
if (buttonsPerRow < 1) buttonsPerRow = 1;
int numRows = ceil((float)buttons.count / buttonsPerRow);
CGFloat requiredHeight = verticalMargin + numRows * (buttonHeight + verticalMargin);
CGRect containerFrame = container.frame;
containerFrame.size.height = requiredHeight;
container.frame = containerFrame;
CGRect selfFrame = self.frame;
selfFrame.size.height = container.frame.origin.y + requiredHeight;
self.frame = selfFrame;
CGFloat availableWidth = containerWidth - (buttonsPerRow * buttonWidth);
CGFloat adjustedHorizontalMargin = availableWidth / (buttonsPerRow + 1);
for (int i = 0; i < buttons.count; i++) {
UIButton *button = buttons[i];
int row = i / buttonsPerRow;
int col = i % buttonsPerRow;
CGFloat x = adjustedHorizontalMargin + col * (buttonWidth + adjustedHorizontalMargin);
CGFloat y = verticalMargin + row * (buttonHeight + verticalMargin);
button.frame = CGRectMake(x, y, buttonWidth, buttonHeight);
}
}
@end
```
## 3. 创建 AMapLinkDemoViewController
### 头文件(AMapLinkDemoViewController.h)
```objc
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface AMapLinkDemoViewController : UIViewController
- (BOOL)handleUrl:(NSURL *)url;
@end
NS_ASSUME_NONNULL_END
```
### 实现文件(AMapLinkDemoViewController.m)
```objc
#import "AMapLinkDemoViewController.h"
#import "AMapLinkDemoNavBarView.h"
#import "AMapLinkDemoEventActionView.h"
#import <MALLMKit/AMapLinkManager.h>
#import <MALLMKit/AMapAuthorizationManager.h>
#import <MALLMKit/AMapLinkConnectConfig.h>
#import "AMapLinkClientObserverManager.h"
#define kAMapAIPCAuthStatus @"kAMapAIPCAuthStatus"
@interface AMapLinkDemoViewController () <AMapLinkDemoEventActionViewDelegate>
@property (nonatomic, assign) BOOL isAuthored;
@property (nonatomic, strong) UITextView *receivedTextView;
@property (nonatomic, strong) AMapLinkDemoNavBarView *navBarView;
@property (nonatomic, strong) AMapLinkDemoEventActionView *eventActionView;
@property (nonatomic, strong) AMapLinkConnectConfig *connectConfig;
@end
@implementation AMapLinkDemoViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.view setBackgroundColor:[UIColor whiteColor]];
self.isAuthored = [[NSUserDefaults standardUserDefaults] boolForKey:kAMapAIPCAuthStatus];
[self initUI];
[self tryLink];
__weak typeof(self) weakSelf = self;
[[AMapLinkClientObserverManager sharedInstance] addObserver:^(NSString * _Nonnull msg) {
[weakSelf appendMessage:msg];
[weakSelf updateInfo];
}];
}
#pragma mark - Link Management
- (void)tryLink {
if (self.isAuthored) {
[self createConnect];
}
}
- (void)openAmap {
__weak typeof(self) weakSelf = self;
[[AMapAuthorizationManager sharedInstance] startAuthenticationWithCallback:^(BOOL success, NSError * _Nonnull error) {
[weakSelf appendMessage:[NSString stringWithFormat:@"%d %@", success, error]];
[weakSelf updateInfo];
}];
}
- (BOOL)handleUrl:(NSURL *)url {
BOOL authResult = [[AMapAuthorizationManager sharedInstance] handleURL:url];
self.isAuthored = authResult;
if (authResult) {
[[NSUserDefaults standardUserDefaults] setBool:authResult forKey:kAMapAIPCAuthStatus];
[self createConnect];
}
return YES;
}
- (void)createConnect {
if (!self.isAuthored) {
return;
}
if ([[AMapLinkManager sharedInstance] isConnected]) {
return;
}
AMapLinkConnectConfig *config = [AMapLinkConnectConfig new];
config.autoReconnect = YES;
config.maxReconnectAttempts = 50;
config.reconnectDelay = 2;
self.connectConfig = config;
[[AMapLinkManager sharedInstance] initWithConnectConfig:config];
[[AMapLinkManager sharedInstance] connect];
}
- (void)disconnect {
[[AMapLinkManager sharedInstance] disconnect];
}
- (void)sendData:(NSDictionary *)data {
if (!data || ![NSJSONSerialization isValidJSONObject:data]) {
return;
}
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data
options:NSJSONWritingSortedKeys
error:&error];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
if (jsonString) {
[self appendMessage:[NSString stringWithFormat:@"writeData: %@", jsonString]];
[[AMapLinkManager sharedInstance] sendDataToClient:jsonString];
}
}
#pragma mark - AMapLinkDemoEventActionViewDelegate
- (void)sendData {
[self sendData:@{ @"text": @"你好呀" }];
}
- (void)startNavi {
[self sendData:@{ @"cmd": @(5), @"requestId": @2222225 }];
}
- (void)changeRideBroadcast {
NSArray *rideValues = @[@"0", @"1"];
NSUInteger randomIndex = arc4random_uniform((uint32_t)rideValues.count);
[self sendData:@{
@"cmd": @(6),
@"data": @{ @"value": rideValues[randomIndex] },
@"requestId": @2222226
}];
}
- (void)changeCarBroadcast {
NSArray *carValues = @[@(0), @(1), @(2), @(6), @(7)];
NSUInteger randomIndex = arc4random_uniform((uint32_t)carValues.count);
[self sendData:@{
@"cmd": @(6),
@"data": @{ @"value": carValues[randomIndex] },
@"requestId": @2222227
}];
}
- (void)changeDestination {
[self sendData:@{
@"cmd": @(4),
@"data": @{
@"lon": @116.397455, @"lat": @39.909187,
@"name": @"天安门", @"poiid": @"B000A60DA1",
@"entranceList": @[ @{ @"lon": @116.397604, @"lat": @39.907697 } ]
},
@"requestId": @2222224
}];
}
- (void)addViaPoint {
[self sendData:@{
@"cmd": @(3),
@"data": @{
@"lon": @116.397455, @"lat": @39.909187,
@"name": @"天安门", @"poiid": @"B000A60DA1",
@"entranceList": @[ @{ @"lon": @116.397604, @"lat": @39.907697 } ]
},
@"requestId": @2222223
}];
}
- (void)clearLog {
self.receivedTextView.text = @"日志已清除";
}
- (void)copyLog {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"复制日志"
message:@"确认要复制日志内容到剪贴板吗?"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消"
style:UIAlertActionStyleCancel
handler:nil];
UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:@"确认"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
[UIPasteboard generalPasteboard].string = self.receivedTextView.text;
[self appendMessage:@"日志内容已复制到剪贴板"];
}];
[alertController addAction:cancelAction];
[alertController addAction:confirmAction];
[self presentViewController:alertController animated:YES completion:nil];
}
#pragma mark - UI
- (void)appendMessage:(id)message {
if ([message isKindOfClass:[NSObject class]]) {
dispatch_async(dispatch_get_main_queue(), ^{
self.receivedTextView.text = [NSString stringWithFormat:@"%@\n----------------------------\n%@",
self.receivedTextView.text, message];
});
}
}
- (void)updateInfo {
dispatch_async(dispatch_get_main_queue(), ^{
BOOL isConnected = [[AMapLinkManager sharedInstance] isConnected];
BOOL isAuthed = self.isAuthored || [[NSUserDefaults standardUserDefaults] boolForKey:kAMapAIPCAuthStatus];
[self.eventActionView updateInfo:@{
@"isConnected": @(isConnected),
@"isAuthored": @(isAuthed)
}];
});
}
- (void)initUI {
NSInteger screenWidth = self.view.bounds.size.width;
NSInteger screenHeight = self.view.bounds.size.height;
// 页面背景色
self.view.backgroundColor = [UIColor colorWithRed:0.96 green:0.96 blue:0.97 alpha:1.0];
// 1. 导航栏
CGFloat statusBarHeight = 20;
if (@available(iOS 11.0, *)) {
UIWindow *window = UIApplication.sharedApplication.windows.firstObject;
statusBarHeight = window.safeAreaInsets.top;
}
CGFloat navBarHeight = statusBarHeight + 44;
AMapLinkDemoNavBarView *navBarView = [[AMapLinkDemoNavBarView alloc] initWithFrame:CGRectMake(0, 0, screenWidth, navBarHeight)];
[navBarView setTitle:@"AMap IPC Link Demo"];
__weak typeof(self) weakSelf = self;
navBarView.onBackTapped = ^{
[weakSelf.navigationController popViewControllerAnimated:YES];
};
[self.view addSubview:navBarView];
self.navBarView = navBarView;
// 2. 操作按钮面板(带卡片容器)
CGFloat panelTop = navBarView.bounds.size.height + 12;
UIView *panelCard = [[UIView alloc] init];
panelCard.backgroundColor = [UIColor whiteColor];
panelCard.layer.cornerRadius = 12;
panelCard.layer.shadowColor = [UIColor blackColor].CGColor;
panelCard.layer.shadowOffset = CGSizeMake(0, 2);
panelCard.layer.shadowOpacity = 0.06;
panelCard.layer.shadowRadius = 8;
AMapLinkDemoEventActionView *eventActionView = [[AMapLinkDemoEventActionView alloc] initWithOriginX:0
originY:0
width:screenWidth - 32];
eventActionView.delegate = self;
panelCard.frame = CGRectMake(16, panelTop, screenWidth - 32, eventActionView.bounds.size.height + 16);
eventActionView.frame = CGRectMake(0, 8, screenWidth - 32, eventActionView.bounds.size.height);
[panelCard addSubview:eventActionView];
[self.view addSubview:panelCard];
self.eventActionView = eventActionView;
// 3. 日志标题
CGFloat logSectionTop = CGRectGetMaxY(panelCard.frame) + 16;
UILabel *logTitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(24, logSectionTop, screenWidth - 48, 22)];
logTitleLabel.text = @"📋 通信日志";
logTitleLabel.font = [UIFont systemFontOfSize:15 weight:UIFontWeightSemibold];
logTitleLabel.textColor = [UIColor colorWithRed:0.3 green:0.3 blue:0.35 alpha:1.0];
[self.view addSubview:logTitleLabel];
// 4. 日志回显区域(卡片样式)
CGFloat logTop = logSectionTop + 30;
CGFloat bottomSafeArea = 34;
if (@available(iOS 11.0, *)) {
UIWindow *window = UIApplication.sharedApplication.windows.firstObject;
bottomSafeArea = window.safeAreaInsets.bottom;
}
UITextView *receivedTextView = [[UITextView alloc] initWithFrame:CGRectMake(16, logTop,
screenWidth - 32,
screenHeight - logTop - bottomSafeArea - 16)];
receivedTextView.text = @"等待通信日志...";
receivedTextView.textColor = [UIColor colorWithRed:0.35 green:0.35 blue:0.4 alpha:1.0];
receivedTextView.font = [UIFont fontWithName:@"Menlo" size:12.5];
receivedTextView.backgroundColor = [UIColor whiteColor];
receivedTextView.textAlignment = NSTextAlignmentLeft;
receivedTextView.editable = NO;
receivedTextView.scrollEnabled = YES;
receivedTextView.textContainerInset = UIEdgeInsetsMake(12, 10, 12, 10);
receivedTextView.layer.cornerRadius = 12;
receivedTextView.layer.shadowColor = [UIColor blackColor].CGColor;
receivedTextView.layer.shadowOffset = CGSizeMake(0, 2);
receivedTextView.layer.shadowOpacity = 0.06;
receivedTextView.layer.shadowRadius = 8;
receivedTextView.clipsToBounds = NO;
[self.view addSubview:receivedTextView];
self.receivedTextView = receivedTextView;
}
@end
```
## 4. Info.plist 配置
### 配置 URL Scheme
在 Info.plist 中添加 URL Types,用于接收高德 APP 的授权回调:
```xml
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>你的URLScheme</string>
</array>
</dict>
</array>
```
### 配置 LSApplicationQueriesSchemes
添加高德地图 APP 的 Scheme,允许跳转:
```xml
<key>LSApplicationQueriesSchemes</key>
<array>
<string>iosamap</string>
</array>
```
## 5. 处理授权回调 URL
在 AppDelegate 或 SceneDelegate 中将 URL 传递给 `AMapLinkDemoViewController` 处理:
### AppDelegate 方式
```objc
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options {
[self.linkDemoViewController handleUrl:url];
return YES;
}
```
### SceneDelegate 方式(iOS 13+)
```objc
- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts {
UIOpenURLContext *context = URLContexts.allObjects.firstObject;
if (context) {
[self.linkDemoViewController handleUrl:context.URL];
}
}
```
## 下一步
- [认证管理](authorization.md) — 授权流程详细说明
- [连接管理](connection.md) — 连接配置与状态管理
- [数据传输与命令](data-transfer.md) — 导航命令与数据收发
FILE:api/logger.md
# 日志管理
通过 `AMapAgentLog` 监听 SDK 内部日志,用于调试和问题排查。
## 设置日志代理
```objc
// 实现 AMapAgentLogProtocol 协议
@interface YourClass () <AMapAgentLogProtocol>
@end
@implementation YourClass
- (void)setupLogging {
[[AMapAgentLog shareInstance] setLogDelegate:self];
}
#pragma mark - AMapAgentLogProtocol
- (void)onLog:(AMapAgentLogLevel)logLevel logContent:(NSString *)logContent {
NSLog(@"[Agent %ld] %@", (long)logLevel, logContent);
}
@end
```
## AMapAgentLogLevel 日志级别
| 级别 | 值 | 说明 |
|------|-----|------|
| `Debug` | 0 | 调试信息 |
| `Info` | 1 | 一般信息 |
| `Warning` | 2 | 警告 |
| `Error` | 3 | 错误 |
| `Fatal` | 4 | 致命错误 |
| `Track` | 5 | 性能排查 |
> 重复调用 `setLogDelegate:` 会覆盖之前的代理。
FILE:api/navi-control.md
# 导航控制 API
通过 `AMapNaviClientManager` 控制导航行为,SDK 和 APP 链路统一接口。
## 停止导航
```objc
[[AMapNaviClientManager shareInstance] stopNavi];
```
## 切换路线
```objc
// routeID 来自查询结果中的路线字典 key
[[AMapNaviClientManager shareInstance] switchRoute:routeID];
```
## 强制刷新路线
重新请求路线数据,刷新后会重新回调路线数据:
```objc
[[AMapNaviClientManager shareInstance] forceRefreshRoute];
```
## 播报模式
```objc
// mode 值:
// 0 — 静音
// 1 — 简洁播报
// 2 — 详细播报
// 6 — 极简播报
// 7 — 智能播报
[[AMapNaviClientManager shareInstance] switchBroadcastMode:2];
```
> **注意**:导航过程中设置播报模式,需在下次算路后生效(如偏航重算、手动刷新)。SDK 链路下,仅驾车支持全部播报模式,骑步行仅支持静音(0)和播报(1)。
## 设置导航视图
用于获取导航跟随模式回调数据:
```objc
// view 可以是 AMapNaviDriveView / AMapNaviRideView / AMapNaviWalkView
[[AMapNaviClientManager shareInstance] setAmapNaviView:driveView];
```
> 切换导航类型后需重新设置。不设置则跟随模式变更不会回调,但导航数据仍可通过 `addNaviDataListener` 获取。
## 获取精简路线信息
获取当前高亮路线从自车位置开始的精简路线 PB 数据:
```objc
// limitPointSize: 限制坐标点数量
AMapNaviPbData *partialRoute = [[AMapNaviClientManager shareInstance] getPartialRouteGroupWithLimitPointSize:100];
```
## 位置更新
持续向 SDK 提供定位数据:
```objc
// 在 CLLocationManager 回调中调用
[[AMapNaviClientManager shareInstance] updateMyLocation:location];
// 可配置最小发送间隔(秒),默认 0 不限制
[AMapNaviClientManager shareInstance].locationUpdateInterval = 1.0;
```
## 相关文档
- [导航数据监听](navi-data-listener.md) — 监听导航过程中的数据回调
- [出行方式配置](transport-mode.md) — 配置导航类型和路线偏好
FILE:api/navi-data-listener.md
# 导航数据监听
通过 `addNaviDataListener` 实时监听导航过程中的各种数据更新。
## PB 数据监听
```objc
// 添加监听
NaviDataCallback callback = ^(AMapNaviPbData *naviData) {
NSLog(@"类型: %ld, 来源: %ld", (long)naviData.type, (long)naviData.source);
};
[[AMapNaviClientManager shareInstance] addNaviDataListener:callback];
// 移除监听(需持有 callback 引用)
[[AMapNaviClientManager shareInstance] removeNaviDataListener:callback];
```
## AMapNaviPbData 属性
| 属性 | 类型 | 说明 |
|------|------|------|
| `data` | `NSData` | 导航 PB 二进制数据 |
| `type` | `AMapNaviDataType` | 数据类型枚举 |
| `source` | `AMapNaviDataSource` | 数据来源 |
## AMapNaviDataType 关键枚举值
| 枚举值 | 值 | 说明 |
|--------|-----|------|
| `CalcSuccess` | 1 | 算路成功 |
| `UpdateRouteGroup` | 2 | 路线数据更新(路线真正应用) |
| `CalcFailed` | 3 | 算路失败 |
| `UpdateNaviInfo` | 4 | 行中导航信息更新 |
| `StartNavi` | 7 | 开始导航 |
| `PlayNaviSound` | 8 | 播报导航信息 |
| `ArrivedWayPoint` | 9 | 到达途经点 |
| `ShowLaneInfo` | 14 | 车道线数据 |
| `HideLaneInfo` | 15 | 车道线隐藏 |
| `UpdateNaviLocation` | 16 | 定位信息更新 |
| `TrackingModeInfo` | 18 | 跟随模式 |
| `HighLightChanged` | 20 | 高亮路线变更 |
| `StopNavi` | 100 | 结束导航 |
| `ArrivedDestination` | 200 | 到达目的地 |
## AMapNaviDataSource 数据来源
| 枚举值 | 值 | 说明 |
|--------|-----|------|
| `Open` | 0 | 开平 SDK 内集成导航 |
| `OpenAgent` | 1 | 开平 Agent SDK |
| `AMap` | 2 | 高德 APP |
## 类型化数据监听
除 PB 原始数据外,还可监听类型化数据(APP 链路):
```objc
[[AMapNaviClientManager shareInstance] addNaviTypeDataListener:^(AMapNaviTypeData *naviTypeData) {
switch (naviTypeData.type) {
case AMapNaviDataTypeUpdateRouteGroup:
NSLog(@"路线数据更新,resultObj: %@", naviTypeData.resultObj);
break;
case AMapNaviDataTypeCalcSuccess:
NSLog(@"算路成功");
break;
case AMapNaviDataTypeStartNavi:
NSLog(@"开始导航");
break;
default:
break;
}
}];
```
## AMapNaviTypeData 属性
| 属性 | 类型 | 说明 |
|------|------|------|
| `resultObj` | `id` | 类型化结果对象,具体类型取决于 `type` |
| `type` | `AMapNaviDataType` | 数据类型枚举 |
| `source` | `AMapNaviDataSource` | 数据来源 |
## 重要注意事项
1. **必须在算路之前设置监听器**,否则可能收不到回调
2. `AMapNaviClientManager` 须正确设置 `naviType` 才能注册对应导航数据监听
3. 导航数据回调可能在子线程,UI 更新需切回主线程
FILE:api/query-result.md
# 查询结果处理
`AMapAgentQueryResult` 是所有查询的统一返回结构,通过 `setQueryResultCallback:` 回调获取。
## AMapAgentQueryResult 属性
| 属性 | 类型 | 说明 |
|------|------|------|
| `actionType` | `AMapAgentQueryResultActionType` | 操作类型(路线/POI/退出导航等) |
| `stateType` | `AMapAgentQueryResultStateType` | 状态(进行中/追加/结束) |
| `resultType` | `AMapAgentQueryResultType` | 结果类型(命令/总结) |
| `summary` | `NSString` | 查询总结文本 |
| `resultObj` | `id` | 结果数据对象(类型取决于 actionType) |
| `errorInfo` | `NSError` | 错误信息(无错误时为 nil) |
| `sessionId` | `NSString` | 查询会话 ID |
| `endPoiName` | `NSString` | 终点名称 |
| `viaPoiItem` | `AMapPOI` | 途经点信息 |
## actionType 与 resultObj 对应关系
| actionType | 含义 | resultObj 类型 |
|------------|------|----------------|
| `RequestRoute` | 行前请求路线 | `NSDictionary<NSNumber*, AMapNaviRoute*>` |
| `RequestRouteInNavi` | 行中请求路线 | `NSDictionary<NSNumber*, AMapNaviRoute*>` |
| `SearchPoi` | POI 搜索 | `AMapPOIResult` |
| `SelectPoiWorkFlow` | 行前 POI 选点 | `AMapPOIResult` |
| `SelectPoiWorkFlowSingle` | 单点选点 | `AMapPOIResult` |
| `RouteSearch` | 行中顺路搜 | `NSArray<AMapRoutePOI*>` |
| `ExitNavi` | 退出导航 | 无 |
| `BreakSession` | 中断会话 | 无 |
| `Refuse` | 拒绝命令 | 无 |
| `ChangeOrViaPoi` | 行中变更POI | 无 |
| `SetAutoListen` | 闲聊指令 | 无 |
| `RequestGuideInfo` | 行中引导 | 无 |
## stateType 状态流转
| 状态 | 说明 |
|------|------|
| `Working` | 查询进行中,可能有中间结果 |
| `Append` | 追加结果(如流式返回) |
| `End` | 查询结束,结果完整 |
## 典型处理模式
```objc
[[AMapAgentClientManager shareInstance] setQueryResultCallback:^(AMapAgentQueryResult *result) {
// 1. 先检查错误
if (result.errorInfo) {
NSLog(@"查询错误: %@", result.errorInfo);
return;
}
// 2. 按 actionType 分发处理
switch (result.actionType) {
case AMapAgentQueryResultActionTypeRequestRoute: {
NSDictionary *routes = result.resultObj;
// 处理路线数据,开始导航
break;
}
case AMapAgentQueryResultActionTypeSearchPoi: {
AMapPOIResult *poiResult = result.resultObj;
NSArray<AMapPOI *> *pois = poiResult.poiItemArray;
// 展示 POI 列表
break;
}
case AMapAgentQueryResultActionTypeExitNavi:
// 退出导航
break;
default:
break;
}
}];
```
## 相关文档
- [智能查询 API](agent-query.md) — 发起查询
- [常见问题排查](../references/troubleshooting.md) — 错误码说明
FILE:api/quick-start.md
# 快速集成指南
## 系统要求
- iOS 11.0+
- 需集成高德地图 SDK 相关组件(AMapNaviKit、AMapSearchKit)
## 1. 添加依赖
在项目中添加 `MALLMKit.a` 静态库依赖。
## 2. 导入头文件
MALLMKit 以静态库(`.a`)形式提供,头文件通过 Header Search Paths 引入:
```objc
#import "AMapAgentClientManager.h"
#import "AMapNaviClientManager.h"
#import "AMapAgentQueryParam.h"
#import "AMapAgentQueryResult.h"
#import "AMapNaviEnv.h"
#import "AMapLinkManager.h"
#import "AMapAuthorizationManager.h"
```
## 3. 初始化(最小可用配置)
```objc
// 1) 设置链路模式:SDK链路(应用内集成)或 APP链路(依赖高德APP)
[AMapAgentClientManager shareInstance].commandDestination = AMapAgentCommandDestinationSDK;
// 2) 设置查询结果回调
[[AMapAgentClientManager shareInstance] setQueryResultCallback:^(AMapAgentQueryResult *queryResult) {
// 处理查询结果,详见 query-result.md
}];
// 3) 配置导航环境
AMapNaviEnv *env = [AMapNaviEnv new];
env.amapNaviType = AMapNaviTypeDrive;
env.multipleRoute = YES;
[AMapNaviClientManager shareInstance].amapNaviEnv = env;
// 4) 重置场景到主图
[[AMapAgentClientManager shareInstance] resetAgentScene:@"home"];
```
## 4. 发起第一次查询
```objc
AMapAgentQueryParam *param = [AMapAgentQueryParam new];
param.queryText = @"附近的加油站";
NSString *sessionId = [[AMapAgentClientManager shareInstance] query:param];
```
## 初始化顺序要求
> **重要**:`AMapAgentClientManager` 和 `AMapNaviClientManager` 必须在 `AMapLinkManager` 之前初始化。
## 两种链路模式
| 模式 | 枚举值 | 特点 |
|------|--------|------|
| **SDK链路** | `AMapAgentCommandDestinationSDK` | 应用内独立运行,不依赖高德APP |
| **APP链路** | `AMapAgentCommandDestinationAPP` | 与高德APP深度集成,需额外建联和授权 |
SDK链路适合大多数场景。如需 APP链路,请参阅 [IPC链路管理](link-client.md)。
## 下一步
- [智能查询 API](agent-query.md) — 了解查询参数与多轮对话
- [查询结果处理](query-result.md) — 处理路线、POI 等返回结果
FILE:api/transport-mode.md
# 出行方式配置
通过 `AMapNaviEnv` 配置导航环境,包括出行方式、路线偏好和常用地点。
## 导航环境配置
`AMapNaviClientManager` 提供两级配置:
| 属性 | 说明 |
|------|------|
| `defaultNaviEnv` | 全局默认配置 |
| `amapNaviEnv` | 当前导航配置(优先级更高) |
```objc
AMapNaviEnv *env = [AMapNaviEnv new];
// 出行方式
env.amapNaviType = AMapNaviTypeDrive; // AMapNaviTypeDrive / AMapNaviTypeRide / AMapNaviTypeWalk
// 路线偏好
env.multipleRoute = YES; // 是否返回多条路线
env.avoidCongestion = NO; // 躲避拥堵
env.avoidHighway = NO; // 躲避高速
env.avoidCost = NO; // 躲避收费
env.prioritiseHighway = NO; // 优先高速
[AMapNaviClientManager shareInstance].amapNaviEnv = env;
```
## 设置家和公司位置
```objc
AMapAgentPOI *home = [AMapAgentPOI new];
home.name = @"我的家";
home.coordinate = CLLocationCoordinate2DMake(39.908823, 116.397470);
home.uid = @"HOME_POI_ID";
env.homeLocation = home;
AMapAgentPOI *work = [AMapAgentPOI new];
work.name = @"我的公司";
work.coordinate = CLLocationCoordinate2DMake(39.918823, 116.407470);
work.uid = @"WORK_POI_ID";
env.workLocation = work;
```
> 未设置家/公司位置时,用户说"回家"/"去公司"会返回 `HomeNotSet` / `CompanyNotSet` 错误。
## 导航类型同步
设置导航类型时需同步更新 `AMapNaviClientManager.naviType`:
```objc
[AMapNaviClientManager shareInstance].naviType = AMapNaviTypeDrive;
[AMapNaviClientManager shareInstance].amapNaviEnv.amapNaviType = AMapNaviTypeDrive;
```
## AMapAgentPOI 属性
| 属性 | 类型 | 说明 |
|------|------|------|
| `name` | `NSString` | POI 名称 |
| `coordinate` | `CLLocationCoordinate2D` | 经纬度坐标 |
| `uid` | `NSString` | POI 唯一标识 |
FILE:references/core-classes.md
# 核心类参考
MALLMKit 对外暴露的公共类(PublicHeaders)与枚举速查表。所有属性和方法均基于源码头文件定义。
## 管理器类(单例)
### AMapAgentClientManager
**头文件**:`AMapAgentClientManager.h` | **获取方式**:`[AMapAgentClientManager shareInstance]`
| 属性/方法 | 类型 | 说明 |
|-----------|------|------|
| `commandDestination` | `AMapAgentCommandDestination` | 链路模式(SDK / APP) |
| `+ configureAgentURL:` | 类方法 | 配置 Agent 服务器 URL |
| `+ currentAgentURL` | 类方法 | 获取当前 Agent URL |
| `- setQueryResultCallback:` | 实例方法 | 设置查询结果回调 |
| `- query:` | 实例方法 | 发起查询,参数为 `AMapAgentQueryParam`,返回 sessionId |
| `- resetAgentScene:` | 实例方法 | 重置场景(home/route/navi/search) |
| `- resetAgentStatus` | 实例方法 | 重置会话状态 |
| `- version` | 实例方法 | 获取版本号 |
| `+ destroy` | 类方法 | 销毁单例 |
### AMapNaviClientManager
**头文件**:`AMapNaviClientManager.h` | **获取方式**:`[AMapNaviClientManager shareInstance]`
| 属性/方法 | 类型 | 说明 |
|-----------|------|------|
| `defaultNaviEnv` | `AMapNaviEnv` | 全局默认导航配置 |
| `amapNaviEnv` | `AMapNaviEnv` | 当前导航配置(优先级更高) |
| `naviType` | `AMapNaviType` | 当前导航类型 |
| `locationUpdateInterval` | `NSTimeInterval` | 定位数据发送最小间隔(秒) |
| `- addNaviDataListener:` | 实例方法 | 添加导航 PB 数据监听 |
| `- removeNaviDataListener:` | 实例方法 | 移除导航 PB 数据监听 |
| `- addNaviTypeDataListener:` | 实例方法 | 添加类型化数据监听(APP 链路) |
| `- removeNaviTypeDataListener:` | 实例方法 | 移除类型化数据监听 |
| `- stopNavi` | 实例方法 | 停止导航 |
| `- switchRoute:` | 实例方法 | 切换路线 |
| `- switchBroadcastMode:` | 实例方法 | 设置播报模式(1简洁/2详细/0静音/6极简/7智能) |
| `- setAmapNaviView:` | 实例方法 | 设置导航视图(用于跟随模式回调) |
| `- updateMyLocation:` | 实例方法 | 更新定位信息 |
| `- forceRefreshRoute` | 实例方法 | 强制重刷路线 |
| `- getPartialRouteGroupWithLimitPointSize:` | 实例方法 | 获取精简路线 PB 数据 |
| `- onNaviManagerDestroyed:` | 实例方法 | 通知导航 Manager 销毁 |
| `+ destroy` | 类方法 | 销毁单例 |
### AMapLinkManager
**头文件**:`AMapLinkManager.h` | **获取方式**:`[AMapLinkManager sharedInstance]` | APP 链路 IPC 建联管理
### AMapAuthorizationManager
**头文件**:`AMapAuthorizationManager.h` | **获取方式**:`[AMapAuthorizationManager sharedInstance]` | APP 链路授权管理
### AMapAgentLog
**头文件**:`AMapAgentLog.h` | **获取方式**:`[AMapAgentLog shareInstance]`
| 方法 | 说明 |
|------|------|
| `- setLogDelegate:` | 设置日志代理(`id<AMapAgentLogProtocol>`) |
**AMapAgentLogProtocol 协议方法**:`- (void)onLog:(AMapAgentLogLevel)logLevel logContent:(NSString *)logContent;`
## 数据模型类
### AMapAgentQueryParam
**头文件**:`AMapAgentQueryParam.h`
| 属性 | 类型 | 说明 |
|------|------|------|
| `queryText` | `NSString` | 查询文本 |
| `lastActionType` | `AMapAgentQueryResultActionType` | 上一次查询的 actionType(多轮对话) |
| `selectedObject` | `id` | 上一次查询的结果对象(多轮对话) |
### AMapAgentQueryResult
**头文件**:`AMapAgentQueryResult.h`
| 属性 | 类型 | 说明 |
|------|------|------|
| `errorInfo` | `NSError *` | 错误信息(nil 表示成功) |
| `sessionId` | `NSString` | 会话 ID |
| `taskId` | `NSString` | 任务 ID |
| `tppTrace` | `NSString` | 服务 tppTrace ID |
| `sequence` | `NSInteger` | 任务序列号 |
| `actionType` | `AMapAgentQueryResultActionType` | 操作类型 |
| `stateType` | `AMapAgentQueryResultStateType` | 流式状态(Working/Append/End) |
| `resultType` | `AMapAgentQueryResultType` | 结果类型(Command/Summary) |
| `summary` | `NSString` | 总结文本 |
| `resultObj` | `id` | 结果对象(类型取决于 actionType) |
| `endPoiName` | `NSString` | 终点名称 |
| `viaPoiItem` | `AMapPOI *` | 途经点信息 |
**resultObj 类型对照**:
- `RequestRoute` → `NSDictionary<NSNumber *, AMapNaviRoute *>`
- `SearchPoi` / `SelectPoiWorkFlow` → `AMapPOIResult`
- `RouteSearch` → `NSArray<AMapRoutePOI *>`
### AMapNaviEnv
**头文件**:`AMapNaviEnv.h`
| 属性 | 类型 | 说明 |
|------|------|------|
| `homeLocation` | `AMapAgentPOI` | 家位置 |
| `workLocation` | `AMapAgentPOI` | 公司位置 |
| `amapNaviType` | `AMapNaviType` | 导航类型 |
| `amapVehicleInfo` | `AMapNaviVehicleInfo` | 车辆信息 |
| `multipleRoute` | `BOOL` | 是否多路径 |
| `avoidCongestion` | `BOOL` | 是否躲避拥堵 |
| `avoidHighway` | `BOOL` | 是否躲避高速 |
| `avoidCost` | `BOOL` | 是否躲避收费 |
| `prioritiseHighway` | `BOOL` | 是否优先高速 |
### 其他数据模型
| 类名 | 头文件 | 说明 |
|------|--------|------|
| `AMapAgentPOI` | `AMapAgentPOI.h` | POI 数据 |
| `AMapPOIResult` | `AMapPOIResult.h` | POI 搜索结果(poiItemArray) |
| `AMapNaviPbData` | `AMapNaviPbData.h` | 导航 PB 数据(data、type、source) |
| `AMapNaviTypeData` | `AMapNaviTypeData.h` | 类型化导航数据(resultObj、type、source) |
| `AMapLinkConnectConfig` | `AMapLinkConnectConfig.h` | 建联配置 |
| `AMapTaxiInfo` | `AMapTaxiInfo.h` | 打车信息 |
## Category
| 类名 | 头文件 | 说明 |
|------|--------|------|
| `AMapPOIExtension+AgentExtension` | `AMapPOIExtension+AgentExtension.h` | POI 扩展属性 |
## 关键枚举
### AMapAgentCommandDestination — 链路模式
| 值 | 说明 |
|----|------|
| `SDK` | 应用内 SDK 链路 |
| `APP` | 高德 APP 链路 |
### AMapAgentQueryResultActionType — 查询操作类型
| 值 | 说明 |
|----|------|
| `RequestRoute` | 行前请求路线 |
| `RequestRouteInNavi` | 行中请求路线 |
| `SearchPoi` | POI 搜索 |
| `SelectPoiWorkFlow` | 行前 POI 选点 |
| `SelectPoiWorkFlowSingle` | 单点选点 |
| `RouteSearch` | 行中顺路搜 |
| `ChangeOrViaPoi` | 行中变更 POI |
| `ExitNavi` | 退出导航 |
| `BreakSession` | 中断会话 |
| `Refuse` | 拒绝命令 |
| `SetAutoListen` | 闲聊指令 |
| `RequestGuideInfo` | 行中引导 |
### AMapAgentQueryResultStateType — 查询状态
| 值 | 说明 |
|----|------|
| `Working` | 进行中 |
| `Append` | 追加结果 |
| `End` | 结束 |
### AMapNaviDataType — 导航数据类型
| 值 | 编号 | 说明 |
|----|------|------|
| `CalcSuccess` | 1 | 算路成功 |
| `UpdateRouteGroup` | 2 | 路线数据更新 |
| `CalcFailed` | 3 | 算路失败 |
| `UpdateNaviInfo` | 4 | 导航信息更新 |
| `StartNavi` | 7 | 开始导航 |
| `PlayNaviSound` | 8 | 播报信息 |
| `ArrivedWayPoint` | 9 | 到达途经点 |
| `HighLightChanged` | 20 | 高亮路线变更 |
| `StopNavi` | 100 | 结束导航 |
| `ArrivedDestination` | 200 | 到达目的地 |
### AMapAgentLogLevel — 日志级别
| 值 | 编号 | 说明 |
|----|------|------|
| `Debug` | 0 | 调试 |
| `Info` | 1 | 信息 |
| `Warning` | 2 | 警告 |
| `Error` | 3 | 错误 |
| `Fatal` | 4 | 致命 |
| `Track` | 5 | 性能排查 |
### AMapAuthorizationErrorCode — 授权错误码
| 值 | 说明 |
|----|------|
| `AppAuthSuccess` | 授权成功 |
| `InvalidAPIKey` | 无效 apiKey |
| `MissingAPIKey` | 缺少 apiKey |
| `NetworkFailed` | 网络异常 |
| `AppNotInstalled` | APP 未安装 |
| `AppOpenFailed` | 跳转失败 |
| `AppAuthFailed` | 授权失败 |
FILE:references/link-core-classes.md
# 核心类参考
MALLMKit 中 IPC Link 相关的公共类速查表。基于 `AMapLinkClientViewController` 实际使用的 API。
## 核心管理类
### AMapLinkManager
**头文件**:`<MALLMKit/AMapLinkManager.h>` | IPC 连接管理器(单例)
| 属性/方法 | 类型 | 说明 |
|-----------|------|------|
| `+ sharedInstance` | 类方法 | 获取单例实例 |
| `- isConnected` | BOOL | 查询当前连接状态 |
| `- initWithConnectConfig:` | 实例方法 | 使用配置初始化连接 |
| `- connect` | 实例方法 | 发起连接 |
| `- disconnect` | 实例方法 | 断开连接 |
| `- sendDataToClient:` | 实例方法 | 发送 JSON 字符串数据 |
### AMapAuthorizationManager
**头文件**:`<MALLMKit/AMapAuthorizationManager.h>` | 授权管理器(单例)
| 属性/方法 | 类型 | 说明 |
|-----------|------|------|
| `+ sharedInstance` | 类方法 | 获取单例实例 |
| `- startAuthenticationWithCallback:` | 实例方法 | 发起授权,跳转高德 APP,回调返回 (BOOL success, NSError *error) |
| `- handleURL:` | 实例方法 | 处理授权回调 URL,返回 BOOL 表示授权结果 |
### AMapLinkConnectConfig
**头文件**:`<MALLMKit/AMapLinkConnectConfig.h>` | 连接配置
| 属性 | 类型 | 说明 |
|------|------|------|
| `autoReconnect` | `BOOL` | 是否自动重连 |
| `maxReconnectAttempts` | `NSUInteger` | 最大重连次数 |
| `reconnectDelay` | `NSTimeInterval` | 重连间隔(秒) |
## 工具类
### AMapLinkClientObserverManager
**头文件**:`AMapLinkClientObserverManager.h` | 数据接收观察者管理(单例)
| 方法 | 说明 |
|------|------|
| `+ sharedInstance` | 获取单例实例 |
| `- addObserver:` | 添加观察者,回调类型为 `void (^)(NSString *msg)` |
用于接收高德 APP 回传的消息数据。
FILE:references/link-error-codes.md
# 错误码参考
MALLMKit IPC Link 相关的错误码参考。
## 授权错误
`AMapAuthorizationManager` 的 `startAuthenticationWithCallback:` 回调中的 `NSError`:
| 场景 | 说明 | 解决方案 |
|------|------|----------|
| 高德 APP 未安装 | 无法跳转授权 | 提示用户安装高德地图 APP |
| 授权被拒绝 | 用户在高德 APP 中拒绝授权 | 引导用户重新授权 |
| URL 回调解析失败 | `handleURL:` 返回 NO | 检查 URL Scheme 配置是否正确 |
## 连接错误
`AMapLinkManager` 连接过程中可能出现的问题:
| 场景 | 说明 | 解决方案 |
|------|------|----------|
| 未授权就建联 | `isAuthored` 为 NO 时调用 `connect` | 先完成授权流程 |
| 重复连接 | 已连接状态下再次调用 `connect` | 通过 `isConnected` 检查状态 |
| 连接断开 | 高德 APP 退出或网络异常 | 配置 `autoReconnect = YES` 自动重连 |
| 重连达到上限 | 超过 `maxReconnectAttempts` 次数 | 提示用户检查高德 APP 状态,按需重新建联 |
## 数据发送错误
| 场景 | 说明 | 解决方案 |
|------|------|----------|
| 未连接时发送 | 连接未建立就调用 `sendDataToClient:` | 先确保 `isConnected == YES` |
| JSON 序列化失败 | 数据不是合法 JSON 对象 | 通过 `isValidJSONObject:` 校验 |
## 错误处理最佳实践
```objc
// 建联前检查授权和连接状态
- (void)createConnect {
if (!self.isAuthored) {
// 需先完成授权
[self openAmap];
return;
}
if ([[AMapLinkManager sharedInstance] isConnected]) {
return;
}
AMapLinkConnectConfig *config = [AMapLinkConnectConfig new];
config.autoReconnect = YES;
config.maxReconnectAttempts = 50;
config.reconnectDelay = 2;
[[AMapLinkManager sharedInstance] initWithConnectConfig:config];
[[AMapLinkManager sharedInstance] connect];
}
```
FILE:references/troubleshooting.md
# 常见问题排查
## 错误码速查
### AMapAgentQueryResultErrorCode
| 错误码 | 值 | 含义 | 解决方案 |
|--------|-----|------|----------|
| `CmdNotSupport` | -20001 | 当前命令不支持 | 检查查询文本是否在支持范围内 |
| `QueryTimeout` | -20002 | 查询超时 | 检查网络连接,重试查询 |
| `HomeNotSet` | -20003 | 家位置未设置 | 通过 `AMapNaviEnv.homeLocation` 设置 |
| `CompanyNotSet` | -20004 | 公司位置未设置 | 通过 `AMapNaviEnv.workLocation` 设置 |
| `CmdTimeout` | -20005 | 命令执行超时 | 检查导航 SDK 状态,重试 |
| `ViaNotFound` | -20006 | 未找到途经点 | 检查途经点查询文本 |
| `DoAction` | -20007 | doAction 参数错误 | 检查传入参数 |
| `RequestRoute` | -20008 | requestRoute 参数错误 | 检查路线请求参数 |
## 常见问题
### Q: 收不到 addNaviDataListener 回调
**原因**:
1. `AMapNaviClientManager` 未正确设置 `naviType`
2. 监听器在算路之后才设置
**解决**:
```objc
// 确保在算路前设置
[AMapNaviClientManager shareInstance].naviType = AMapNaviTypeDrive;
[[AMapNaviClientManager shareInstance] addNaviDataListener:callback];
// 然后再发起算路
```
### Q: setAmapNaviView 是否必须调用
**不必须**。`setAmapNaviView` 仅用于获取导航跟随模式回调数据。导航数据通过 `addNaviDataListener` 回调,不依赖 NaviView 设置。切换导航类型后需重新设置。
### Q: SDK 链路 vs APP 链路如何选择
| 维度 | SDK 链路 | APP 链路 |
|------|----------|----------|
| 依赖 | 不依赖高德 APP | 需安装高德 APP |
| 功能 | 独立运行 | 可享受高德 APP 完整功能 |
| 集成复杂度 | 低 | 需额外建联和授权 |
### Q: 初始化顺序错误导致崩溃
**正确顺序**:
1. `AMapAgentClientManager` — 最先初始化
2. `AMapNaviClientManager` — 其次
3. `AMapLinkManager` — 最后(仅 APP 链路)
### Q: destroy 返回 NO
单例仍被外部强引用。检查是否有 property 或变量持有了单例引用,释放后重试。
### Q: 导航视图切换注意事项
1. 移除旧导航视图
2. 创建新导航视图并设置 delegate
3. 调用 `setAmapNaviView:` 重新绑定
4. 更新 `naviType` 和 `amapNaviEnv.amapNaviType`
5. 添加新的 DataRepresentative
### Q: UI 更新崩溃
查询结果回调可能在子线程,UI 更新需切回主线程:
```objc
dispatch_async(dispatch_get_main_queue(), ^{
[self updateUIWithResult:queryResult];
});
```
FILE:references/voice-commands.md
# 语音指令参考
Agent SDK 支持的自然语言指令示例,按场景分类。
## 行前场景(home / route)
### 目的地查询
- "去西藏"
- "去颐和园"
- "回家" / "去公司"
- "开车去颐和园需要多久"
### POI 搜索
- "附近的肯德基"
- "附近的加油站"
- "找个停车场"
### 选择操作(多轮对话)
- "第一个"
- "去最近的那个"
## 行中场景(navi)
### 途经点
- "添加加油站为途经点"
- "顺路加个加油站"
### 终点变更
- "修改终点为颐和园"
- "换个目的地"
### 顺路搜索
- "顺路搜下加油站"
- "沿途有没有服务区"
### 导航控制
- "退出导航"
- "切换路线"
## 通用指令
- 支持自然语言表达,SDK 会自动解析意图
- 多轮对话需设置 `lastActionType` 和 `selectedObject`
- 行中指令需先通过 `resetAgentScene:@"navi"` 切换到行中场景
通过 CLI 命令行参数实时操控运行在容器中的高德地图 JSAPI 2.0 实例, 支持地图状态控制、路径规划、POI 搜索等,所有操作均以结构化 JSON 输出,适合 AI Agent 驱动的地图可视化交互场景。
---
name: amap-cli-skill
display_name: Gaode Map CLI - 高德官方命令行工具 Skill
description: >-
通过 CLI 命令行参数实时操控运行在容器中的高德地图 JSAPI 2.0 实例,
支持地图状态控制、路径规划、POI 搜索等,所有操作均以结构化 JSON 输出,适合 AI Agent 驱动的地图可视化交互场景。
metadata:
openclaw:
primaryEnv: AMAP_KEY
requiredBinaries:
- node
- npm
requiredPackages:
- name: "@amap-lbs/amap-gui"
installCmd: "npm install -g @amap-lbs/amap-gui@latest"
---
# AMap GUI — 地图容器 CLI 命令行参数模式
通过命令行实时操控运行在 Electron 容器中的高德地图 JSAPI 2.0 实例。
## 前置条件
### 读取并导出 API Key(优先执行)
**在任何操作前,必须先确保 `AMAP_KEY` 已在当前 shell 环境中生效。**
OpenClaw 的 skill env 注入不一定对 agent 的 exec 环境生效,因此需要主动读取配置并 export。
执行以下命令,从 OpenClaw 配置中读取 Key 并导出到当前环境:
```bash
# 1. 检查环境变量是否已注入
echo "AMAP_KEY=AMAP_KEY"
# 2. 若为空,从 OpenClaw 配置文件读取
if [ -z "$AMAP_KEY" ]; then
CONFIG_FILE="$HOME/.openclaw/openclaw.json"
if [ -f "$CONFIG_FILE" ]; then
AMAP_KEY=$(node -e "
const c = require('$CONFIG_FILE');
const env = c?.skills?.entries?.['amap-cli-skill']?.env || {};
console.log(env.AMAP_KEY || '');
" 2>/dev/null)
AMAP_SECURITY_KEY=$(node -e "
const c = require('$CONFIG_FILE');
const env = c?.skills?.entries?.['amap-cli-skill']?.env || {};
console.log(env.AMAP_SECURITY_KEY || '');
" 2>/dev/null)
export AMAP_KEY
export AMAP_SECURITY_KEY
fi
fi
# 仅输出是否成功,不泄露 Key 内容
if [ -n "$AMAP_KEY" ]; then
echo "AMAP_KEY: configured"
else
echo "AMAP_KEY: not set"
fi
```
**判断逻辑**:
- `AMAP_KEY` 读取成功且非空 → 继续后续步骤
- `AMAP_KEY` 仍为空 → 提示用户在 OpenClaw WebGUI 设置页面配置 `AMAP_KEY`(申请地址:https://lbs.amap.com),配置完成后重试
- `AMAP_SECURITY_KEY` 为空 → 不阻断流程,但新版 Key 可能需要它,建议一并配置
- 两个变量 export 后全局生效,所有后续 `amap-gui` 命令**无需再加 `AMAP_KEY=xxx` 前缀**
### 安装 amap-gui
首先确认 `amap-gui` CLI 是否已安装,若未安装则执行安装:
```bash
# 检查是否已安装(跨平台兼容)
amap-gui --version || npm install -g @amap-lbs/amap-gui@latest
```
> 如果 `amap-gui --version` 执行失败(命令不存在),必须先执行 `npm install -g @amap-lbs/amap-gui@latest` 安装后再继续。
>
> **安全提示**:`@amap-lbs/amap-gui` 是高德地图官方发布的 npm 包([npm 主页](https://www.npmjs.com/package/@amap-lbs/amap-gui)),安装前建议确认包名无误,避免 typosquatting 攻击。
### 必须先配置高德地图 API Key(两个)
`amap-gui` 需要高德地图开放平台的 Key 才能加载地图。**支持两种配置方式,任选其一。**
| 环境变量 | 是否必须 | 说明 |
|----------|----------|------|
| `AMAP_KEY` | 必须 | Web JS API Key |
| `AMAP_SECURITY_KEY` | 推荐设置 | JS API 安全密钥(部分账号类型必须) |
#### 方式一:通过 OpenClaw WebGUI 页面配置(推荐)
在 OpenClaw 的 WebGUI 设置页面中,直接填写以下环境变量:
- `AMAP_KEY` — 填入你的高德 Web JS API Key
- `AMAP_SECURITY_KEY` — 填入对应的安全密钥(可选但推荐)
配置后无需手动执行 `export`,OpenClaw 会自动将其注入到运行环境中。
#### 方式二:通过终端手动配置
```bash
# 检查是否已设置
# macOS / Linux:
echo $AMAP_KEY
echo $AMAP_SECURITY_KEY
# Windows (PowerShell):
# echo $env:AMAP_KEY
# echo $env:AMAP_SECURITY_KEY
# 若未设置,立即配置(申请地址:https://lbs.amap.com)
# macOS / Linux:
export AMAP_KEY=your_amap_web_js_key
export AMAP_SECURITY_KEY=your_amap_security_key
# Windows (PowerShell):
# $env:AMAP_KEY="your_amap_web_js_key"
# $env:AMAP_SECURITY_KEY="your_amap_security_key"
```
**判断逻辑**:
- `AMAP_KEY` 已设置(任意方式)→ 可继续后续步骤
- `AMAP_KEY` 未设置 → **必须先让用户配置**,否则 GUI 启动后地图无法加载,显示错误
- `AMAP_SECURITY_KEY` 未设置 → 默认为空字符串(老版 Key 可正常使用,新版 Key 需要设置)
> 若用户尚未申请 Key,引导其前往 [lbs.amap.com](https://lbs.amap.com) 创建「Web端(JS API)」类型的 Key,同时在控制台获取对应的安全密钥。
### 前置判断:容器未启动则先主动启动
**在执行任何地图操作之前**,必须先做前置判断:
1. **确认 AMAP_KEY 已设置**(见上方)
2. **检查状态**:
```bash
amap-gui status
```
3. **判断逻辑**:
- 若返回 `status: "not_running"` → 容器未运行
- 若返回 `status: "running"` 且 `mapReady: true` → 可以执行命令
4. **若未运行,主动执行启动**(不要依赖自动启动,显式执行):
```bash
amap-gui start
```
5. **等待就绪**:`start` 命令会阻塞直到地图就绪(约 3-8 秒),返回 `mapReady: true` 后再继续后续命令。
**注意**:不采用自动/后台静默启动方式,由 Agent 在检测到未运行时显式执行 `amap-gui start`。
## 命令格式
```
amap-gui <command> [--option value ...]
```
**生命周期命令**(无需参数):
```bash
amap-gui status # 检查容器状态
amap-gui start # 启动容器(阻塞至就绪)
amap-gui stop # 停止容器
```
**status 返回示例**(容器运行中):
```json
{
"success": true,
"data": {
"status": "running",
"port": 9800,
"mapReady": true,
"uptime": 125
},
"error": null
}
```
**status 返回示例**(容器未运行):
```json
{
"success": true,
"data": {
"status": "not_running"
},
"error": null
}
```
**start 返回示例**:
```json
{
"success": true,
"data": {
"status": "running",
"port": 9800,
"mapReady": true
},
"error": null
}
```
**stop 返回示例**:
```json
{
"success": true,
"data": {
"status": "stopped"
},
"error": null
}
```
**交互感知命令**(无需参数):
```bash
amap-gui getLastEvent # 获取用户最后一次地图交互事件
```
**地图操作命令**(通过命令行参数传参,返回 `CommandResult<T>` JSON):
```bash
amap-gui mapState [--option value] # 地图视图控制
amap-gui route [--option value] # 路径规划
amap-gui searchPOI [--option value] # POI 搜索
```
**结果输出原则**:从容器准确获取 JSON 状态/结果,解析后以文字告知用户,不需要截图。
| 命令 | 解析字段 | 告知用户 |
|------|----------|----------|
| `mapState` | center, zoom, style | 当前中心、缩放、样式 |
| `searchPOI` | pois | 名称、地址、距离、类型 |
| `route` | summary.distance, summary.time, summary.steps | 里程、耗时、路线步骤 |
## 核心命令
### 地图状态控制 — mapState
```bash
# 获取当前状态
amap-gui mapState --action get
# 设置视角
amap-gui mapState --action set --center 116.397,39.909 --zoom 15 --style dark
amap-gui mapState --action set --center 121.473,31.230 --zoom 13 --rotation 45 --pitch 60
```
**参数**:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `--action` | `get` \| `set` | No | 操作类型,默认 `get` |
| `--center` | `lng,lat` | No | 中心点坐标(经度,纬度) |
| `--zoom` | `3-20` | No | 缩放级别 |
| `--rotation` | `0-360` | No | 旋转角度 |
| `--pitch` | `0-83` | No | 俯仰角度 |
| `--style` | `string` | No | 地图样式 |
**可用样式**:`normal` `dark` `light` `whitesmoke` `fresh` `grey` `graffiti` `macaron` `blue` `darkblue` `wine`
> **注意**:命令行模式下 `--center` 仅接受 `lng,lat` 坐标格式,不支持地名。如需使用地名,请使用 `--json` 模式。
**mapState get 返回示例**:
```json
{
"success": true,
"data": {
"center": [116.397428, 39.90923],
"zoom": 15,
"rotation": 0,
"pitch": 0,
"style": "normal",
"bounds": {
"southWest": [116.384258, 39.902195],
"northEast": [116.410598, 39.916265]
}
},
"error": null
}
```
| 返回字段 | 类型 | 说明 |
|----------|------|------|
| `data.center` | `[lng, lat]` | 当前地图中心点坐标 |
| `data.zoom` | `number` | 当前缩放级别 |
| `data.rotation` | `number` | 当前旋转角度 |
| `data.pitch` | `number` | 当前俯仰角度 |
| `data.style` | `string` | 当前地图样式名称 |
| `data.bounds` | `object` | 当前可视区域边界(西南角、东北角坐标) |
**mapState set 返回示例**:
```json
{
"success": true,
"data": {
"center": [121.473701, 31.230416],
"zoom": 13,
"rotation": 45,
"pitch": 60,
"style": "dark",
"bounds": {
"southWest": [121.420135, 31.192847],
"northEast": [121.527267, 31.267985]
}
},
"error": null
}
```
> 设置成功后返回的是**设置后的实际地图状态**,可用于确认视角是否已正确应用。
### 路径规划 — route
```bash
# 驾车
amap-gui route --from 北京南站 --to 天安门 --type driving
# 驾车(带途经点)
amap-gui route --from 北京南站 --to 首都机场T3 --type driving --waypoints 天安门,王府井 --policy fastest
# 步行
amap-gui route --from 故宫博物院 --to 景山公园 --type walking
# 骑行
amap-gui route --from 北京大学 --to 清华大学 --type riding
# 公交(city 必填)
amap-gui route --from 北京站 --to 中关村 --type transit --city 北京
# 使用坐标
amap-gui route --from 116.378,39.865 --to 116.397,39.909 --type driving
# 自定义显示名称
amap-gui route --from 116.378,39.865 --from-name 北京南站 --to 116.397,39.909 --to-name 天安门 --type driving
```
**参数**:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `--from` | `地名` 或 `lng,lat` | Yes | 起点(地名或坐标) |
| `--from-name` | `string` | No | 起点显示名称(配合坐标使用) |
| `--to` | `地名` 或 `lng,lat` | Yes | 终点(地名或坐标) |
| `--to-name` | `string` | No | 终点显示名称(配合坐标使用) |
| `--type` | `string` | Yes | 出行方式:`driving` `walking` `riding` `transit` |
| `--waypoints` | `p1,p2,...` | No | 逗号分隔的途经点(仅 driving,最多 16 个) |
| `--policy` | `string` | No | 驾车策略:`fastest` `least_fee` `shortest` `no_highway` `avoid_jam` |
| `--strategy` | `string` | No | 公交策略:`fastest` `least_cost` `least_walk` `most_comfort` `no_subway` |
| `--city` | `string` | transit 必填 | 城市名(公交模式必须指定) |
**地图效果**:规划完成后自动绘制路线(带描边+方向箭头),标记起点(绿色)、途经点(蓝色)、终点(红色)。
**驾车路线返回示例**:
```bash
amap-gui route --from 北京南站 --to 天安门 --type driving
```
```json
{
"success": true,
"data": {
"type": "driving",
"from": {
"name": "北京南站",
"position": [116.378888, 39.865026]
},
"to": {
"name": "天安门",
"position": [116.397477, 39.908692]
},
"summary": {
"distance": 8500,
"time": 1260,
"tolls": 0,
"steps": [
{ "instruction": "从北京南站出发,沿开阳路向北行驶500米", "distance": 500, "time": 60 },
{ "instruction": "右转进入马连道南街,行驶1.2公里", "distance": 1200, "time": 180 },
{ "instruction": "左转进入广安门内大街,行驶2.8公里", "distance": 2800, "time": 420 },
{ "instruction": "沿前门西大街行驶1.5公里", "distance": 1500, "time": 240 },
{ "instruction": "到达天安门", "distance": 0, "time": 0 }
]
}
},
"error": null
}
```
| 返回字段 | 类型 | 说明 |
|----------|------|------|
| `data.type` | `string` | 出行方式 |
| `data.from` | `object` | 起点信息(名称 + 解析后的坐标) |
| `data.to` | `object` | 终点信息(名称 + 解析后的坐标) |
| `data.summary.distance` | `number` | 总距离(米) |
| `data.summary.time` | `number` | 预计耗时(秒) |
| `data.summary.tolls` | `number` | 过路费(元,仅驾车) |
| `data.summary.steps[]` | `array` | 路线步骤列表 |
| `steps[].instruction` | `string` | 该步骤的文字导航指引 |
| `steps[].distance` | `number` | 该步骤距离(米) |
| `steps[].time` | `number` | 该步骤耗时(秒) |
**步行路线返回示例**:
```bash
amap-gui route --from 故宫博物院 --to 景山公园 --type walking
```
```json
{
"success": true,
"data": {
"type": "walking",
"from": {
"name": "故宫博物院",
"position": [116.397029, 39.917839]
},
"to": {
"name": "景山公园",
"position": [116.396794, 39.924908]
},
"summary": {
"distance": 850,
"time": 720,
"steps": [
{ "instruction": "从故宫博物院北门出发,向北步行200米", "distance": 200, "time": 170 },
{ "instruction": "沿景山前街向北步行400米", "distance": 400, "time": 340 },
{ "instruction": "到达景山公园南门", "distance": 250, "time": 210 }
]
}
},
"error": null
}
```
**公交路线返回示例**:
```bash
amap-gui route --from 北京站 --to 中关村 --type transit --city 北京
```
```json
{
"success": true,
"data": {
"type": "transit",
"from": {
"name": "北京站",
"position": [116.427113, 39.903147]
},
"to": {
"name": "中关村",
"position": [116.310905, 39.981901]
},
"summary": {
"distance": 18200,
"time": 3360,
"steps": [
{ "instruction": "步行380米到达北京站地铁站", "distance": 380, "time": 320 },
{ "instruction": "乘坐地铁2号线(外环),经过4站到达西直门站", "distance": 7200, "time": 960 },
{ "instruction": "站内换乘地铁4号线大兴线(安河桥北方向),经过3站到达海淀黄庄站", "distance": 5800, "time": 720 },
{ "instruction": "步行650米到达中关村", "distance": 650, "time": 540 }
]
}
},
"error": null
}
```
### POI 搜索 — searchPOI
```bash
# 关键词搜索
amap-gui searchPOI --keyword 星巴克 --city 北京
# 周边搜索(坐标 + 半径)
amap-gui searchPOI --keyword 咖啡 --center 120.15,30.28 --radius 1000
# 分页
amap-gui searchPOI --keyword 酒店 --city 上海 --pageSize 5 --pageIndex 2
```
**参数**:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `--keyword` | `string` | Yes | 搜索关键词 |
| `--city` | `string` | No | 搜索城市 |
| `--center` | `lng,lat` | No | 周边搜索中心坐标(不传则为关键词搜索) |
| `--radius` | `number` | No | 周边搜索半径(米),默认 3000 |
| `--pageSize` | `number` | No | 每页数量,默认 10 |
| `--pageIndex` | `number` | No | 页码,默认 1 |
> **注意**:命令行模式下 `--center` 仅接受 `lng,lat` 坐标格式,不支持地名。如需使用地名作为搜索中心,请使用 `--json` 模式。
**地图效果**:搜索结果自动标记在地图上(分类图标),点击可查看详情弹窗。
**关键词搜索返回示例**:
```bash
amap-gui searchPOI --keyword 星巴克 --city 北京
```
```json
{
"success": true,
"data": {
"keyword": "星巴克",
"city": "北京",
"total": 238,
"pageSize": 10,
"pageIndex": 1,
"pois": [
{
"name": "星巴克(王府井大街店)",
"address": "王府井大街138号新东安广场1层",
"location": [116.410156, 39.913889],
"tel": "010-65281368",
"type": "餐饮服务;咖啡厅;星巴克",
"id": "B000A83M61"
},
{
"name": "星巴克(国贸商城店)",
"address": "建国门外大街1号国贸商城B1层",
"location": [116.460579, 39.908775],
"tel": "010-65052638",
"type": "餐饮服务;咖啡厅;星巴克",
"id": "B000A8WSBP"
},
{
"name": "星巴克(三里屯太古里店)",
"address": "三里屯路19号三里屯太古里南区1层S1-12b",
"location": [116.454872, 39.933743],
"tel": "010-64176658",
"type": "餐饮服务;咖啡厅;星巴克",
"id": "B000A7BKQG"
}
]
},
"error": null
}
```
**周边搜索返回示例**:
```bash
amap-gui searchPOI --keyword 咖啡 --center 120.15,30.28 --radius 1000
```
```json
{
"success": true,
"data": {
"keyword": "咖啡",
"center": [120.15, 30.28],
"radius": 1000,
"total": 15,
"pageSize": 10,
"pageIndex": 1,
"pois": [
{
"name": "Manner Coffee(西湖银泰店)",
"address": "延安路98号西湖银泰城B1层",
"location": [120.152836, 30.279412],
"tel": "0571-87651234",
"type": "餐饮服务;咖啡厅;咖啡厅",
"distance": 180,
"id": "B0FFHW1N50"
},
{
"name": "星巴克(湖滨银泰店)",
"address": "东坡路7号湖滨银泰in77 B区1层",
"location": [120.153921, 30.281035],
"tel": "0571-87068890",
"type": "餐饮服务;咖啡厅;星巴克",
"distance": 450,
"id": "B0FFH8XKQP"
}
]
},
"error": null
}
```
| 返回字段 | 类型 | 说明 |
|----------|------|------|
| `data.keyword` | `string` | 搜索关键词 |
| `data.city` | `string` | 搜索城市(关键词搜索时) |
| `data.center` | `[lng, lat]` | 搜索中心坐标(周边搜索时) |
| `data.radius` | `number` | 搜索半径(周边搜索时) |
| `data.total` | `number` | 匹配结果总数 |
| `data.pageSize` | `number` | 每页数量 |
| `data.pageIndex` | `number` | 当前页码 |
| `data.pois[]` | `array` | POI 结果列表 |
| `pois[].name` | `string` | POI 名称 |
| `pois[].address` | `string` | POI 地址 |
| `pois[].location` | `[lng, lat]` | POI 坐标 |
| `pois[].tel` | `string` | 联系电话 |
| `pois[].type` | `string` | POI 类型分类 |
| `pois[].distance` | `number` | 距搜索中心的距离(米,仅周边搜索) |
| `pois[].id` | `string` | POI 唯一标识 |
### getLastEvent — 获取用户最后一次地图交互事件
```bash
amap-gui getLastEvent
```
无需参数,直接调用。返回用户在 GUI 上最后一次交互的事件信息。
**事件类型**:
| `type` | 触发方式 | 返回字段 |
|--------|----------|----------|
| `map_click` | 点击地图空白处 | `position` |
| `poi_click` | 点击地图上的 POI 标记 | `title` + `address` + `position` |
| `poi_select` | 在左侧搜索结果列表中选中 | `title` + `address` + `position` |
**返回字段说明**:
| 字段 | 说明 |
|------|------|
| `lastEvent.hasEvent` | 是否有事件记录(`false` 表示用户尚未操作)|
| `lastEvent.type` | 事件类型(见上表)|
| `lastEvent.title` | POI 名称(`poi_click` / `poi_select` 时有值)|
| `lastEvent.address` | POI 地址(`poi_click` / `poi_select` 时有值)|
| `lastEvent.position` | 坐标 `[lng, lat]`,所有事件类型均有值 |
**返回示例**:
```json
{
"success": true,
"data": {
"lastEvent": {
"hasEvent": true,
"type": "poi_select",
"title": "故宫博物院",
"address": "景山前街4号",
"position": [116.397029, 39.917839]
}
},
"error": null
}
```
**典型用法**:用户在地图上点选某地点后,AI 通过 `getLastEvent` 获取位置,再衔接路线规划等操作,无需用户重复说出地名。
```bash
# 用户在 POI 面板点选了一家餐厅
amap-gui getLastEvent
# → type: poi_select, title: "某餐厅", position: [116.488778, 40.002995]
# AI 用获取到的坐标直接规划路线
amap-gui route --from 北京站 --to 116.488778,40.002995 --to-name 某餐厅 --type driving
```
## 命令行参数 vs JSON 模式对比
| 特性 | 命令行参数模式 | JSON 模式 |
|------|---------------|-----------|
| **地名作为坐标** | `--from`/`--to` 支持地名 | `position`/`center` 支持地名 |
| **地名作为搜索中心** | ❌ `--center` 仅支持坐标 | ✅ `center` 支持地名 |
| **地名作为地图中心** | ❌ `--center` 仅支持坐标 | ✅ `center` 支持地名 |
| **途经点** | `--waypoints p1,p2` 逗号分隔 | `waypoints` 数组 |
| **优先级** | 低 | 高(`--json` 会覆盖其他参数) |
| **适用场景** | 简单命令、快速操作 | 复杂参数、精确控制 |
## 关键规则
1. **前置判断** — 操作前先 `amap-gui status`;若未运行则显式执行 `amap-gui start`,确认 `mapReady: true` 后再继续
2. **route 的 `--from`/`--to` 支持地名** — 直接传地名字符串,容器内部自动 geocode
3. **mapState 和 searchPOI 的 `--center` 仅支持坐标** — 格式为 `lng,lat`,如 `116.397,39.909`
4. **坐标格式** — `经度,纬度`(lng,lat),如 `116.397428,39.90923`
5. **transit 必须传 `--city`** — 公交模式必须指定城市
6. **`--waypoints` 仅 driving** — 途经点只有驾车模式支持,多个途经点用逗号分隔
7. **不需要 clear 命令** — 新命令自动清除上一次的路线/标记
8. **`--json` 优先** — 当 `--json` 与其他参数同时使用时,`--json` 的值优先
9. **命令名大小写不敏感** — `searchpoi`、`searchPOI`、`SearchPOI` 均等效,`mapstate` 等同 `mapState`,`getlastevent` 等同 `getLastEvent`
10. **停止容器** — 完成后用 `amap-gui stop` 停止
## 典型工作流
**场景 1:用户想看某地的地图**
```bash
amap-gui status
# → not_running → 先启动
amap-gui start
# → mapReady: true
amap-gui mapState --action set --center 121.491,31.233 --zoom 15 --pitch 45 --style dark
```
**场景 2:用户想从 A 到 B 怎么走**
```bash
amap-gui route --from 北京南站 --to 首都机场T3 --type driving
```
**场景 3:用户想找附近的 XX**
```bash
amap-gui searchPOI --keyword 咖啡 --center 120.155,30.274 --radius 1000
```
**场景 4:连续操作 — 搜索后导航**
```bash
amap-gui searchPOI --keyword 故宫博物院 --city 北京
# 从结果中取坐标
amap-gui route --from 王府井 --to 116.397029,39.917839 --to-name 故宫博物院 --type walking
```
**场景 5:用户点选地图后导航**
```bash
# 用户在地图上点选了目的地
amap-gui getLastEvent
# → position: [116.488778, 40.002995], title: "某餐厅"
# 直接用坐标规划路线
amap-gui route --from 北京站 --to 116.488778,40.002995 --to-name 某餐厅 --type driving
```
**场景 6:完成后停止**
```bash
amap-gui stop
```
高德地图综合服务,支持POI搜索、路径规划、旅游规划、周边搜索和热力图数据可视化
---
name: amap-lbs-skill
display_name: Gaode Map LBS - 高德官方地图综合服务 Skill
description: 高德地图综合服务,支持POI搜索、路径规划、旅游规划、周边搜索和热力图数据可视化
version: 2.0.1
metadata:
openclaw:
requires:
env:
- AMAP_WEBSERVICE_KEY
bins:
- node
- python3
primaryEnv: AMAP_WEBSERVICE_KEY
homepage: https://lbs.amap.com/api/webservice/summary
install:
- kind: node
package: axios
bins: []
---
# 高德地图综合服务 Skill
高德地图综合服务向开发者提供完整的地图数据服务,包括地点搜索、路径规划、旅游规划和数据可视化等功能。
## 功能特性
- 🔍 POI(地点)搜索功能
- 🏙️ 支持关键词搜索、城市限定、类型筛选
- 📍 支持周边搜索(基于坐标和半径)
- 🛣️ 路径规划(步行、驾车、骑行、公交)
- 🗺️ 智能旅游规划助手
- 🔥 热力图数据可视化
- 🔗 地图可视化链接生成
- 💾 配置本地持久化存储
- 🎯 自动管理高德 Web Service Key
## 首次配置
首次使用时需要配置高德 Web Service Key:
1. 访问 [高德开放平台](https://lbs.amap.com/api/webservice/create-project-and-key) 创建应用并获取 Key
2. 设置环境变量:`export AMAP_WEBSERVICE_KEY=your_key`
3. 或运行时自动提示输入并保存到本地配置文件
当用户想要搜索地址、地点、周边信息(如美食、酒店、景点等)、规划路线或可视化数据时,使用此 skill。
## 触发条件
用户表达了以下意图之一:
- 搜索某类地点或某个确定地点(如"搜美食"、"找酒店"、"天安门在哪")
- 基于某个位置搜索周边(如"西直门周边美食"、"北京南站附近酒店")
- 规划路线(如"从天安门到故宫怎么走"、"规划驾车路线")
- 旅游规划(如"帮我规划北京一日游"、"杭州西湖游览路线")
- 包含"搜"、"找"、"查"、"附近"、"周边"、"路线"、"规划"等关键词
- 希望将地理数据可视化为热力图(如"生成热力图"、"用这份数据做热力图展示")
## 场景判断
收到用户请求后,先判断属于哪个场景:
- **场景一**:用户搜索一个**明确的类别**(美食、酒店)或**确定的地点**(天安门、西湖),没有指定"在哪个位置附近"
- **场景二**:用户搜索**某个位置周边**的某类地点,输入中同时包含「位置」和「搜索类别」两个要素(如"西直门周边美食"、"北京南站附近酒店")
- **场景三**:热力图数据可视化
- **场景四**:POI 详细搜索(使用 Web 服务 API)
- **场景五**:路径规划
- **场景六**:智能旅游规划
---
## 场景一:明确关键词搜索
直接搜索一个类别或地点,不涉及特定位置的周边搜索。
**URL 格式:**
```
https://www.amap.com/search?query={关键词}
```
- **域名**:`www.amap.com`
- **路由**:`/search`
- **参数**:`query` = 搜索关键词
### 执行步骤
1. **发送埋点统计请求**:在执行操作前,发送以下请求进行埋点统计:
```bash
curl -s "https://restapi.amap.com/v3/log/init?eventId=skill.call&product=skill_openclaw&platform=JS&label=keyword-search&value=call"
2. **提取关键词**:从用户输入中识别出核心搜索词,去掉"搜"、"找"等修饰词
3. **生成 URL**:拼接 `https://www.amap.com/search?query={关键词}`
4. **返回链接给用户**
### 示例
| 用户输入 | 提取关键词 | 生成 URL |
|---------|-----------|---------|
| 搜美食 | 美食 | `https://www.amap.com/search?query=美食` |
| 找酒店 | 酒店 | `https://www.amap.com/search?query=酒店` |
| 天安门在哪 | 天安门 | `https://www.amap.com/search?query=天安门` |
| 找个加油站 | 加油站 | `https://www.amap.com/search?query=加油站` |
### 回复模板
```
🔍 已为你生成高德地图搜索链接:
https://www.amap.com/search?query={关键词}
点击链接即可查看搜索结果。
```
---
## 场景二:基于位置的周边搜索
用户想搜索**某个位置周边**的某类地点。需要先通过地理编码 API 获取该位置的经纬度,再拼接带坐标的搜索链接。
**前置条件:** 需要用户提供高德开放平台的 API Key。
### 执行步骤
#### 第零步:发送埋点统计请求
在执行任何操作前,先发送以下请求进行埋点统计:
```bash
curl -s "https://restapi.amap.com/v3/log/init?eventId=skill.call&product=skill_openclaw&platform=JS&label=nearby-search&value=call"
#### 第一步:解析用户输入
从用户输入中拆分出两个要素:
- **位置**:用户指定的中心位置(如"西直门"、"北京南站")
- **搜索类别**:要搜索的内容(如"美食"、"酒店")
| 用户输入 | 位置 | 搜索类别 |
|---------|------|---------|
| 西直门周边美食 | 西直门 | 美食 |
| 北京南站附近酒店 | 北京南站 | 酒店 |
| 天坛周边有什么好吃的 | 天坛 | 美食 |
#### 第二步:检查 API Key
- 如果用户之前未提供过 Key,**先提示用户提供高德 API Key**,等待用户回复后再继续
- 如果用户已提供 Key,直接使用
**请求 Key 的回复模板:**
```
🔑 搜索「{位置}」周边的{搜索类别}需要使用高德 API,请提供你的高德开放平台 API Key。
(如果还没有 Key,可以在 https://lbs.amap.com 注册并创建应用获取)
```
#### 第三步:调用地理编码 API 获取经纬度
**API 格式:**
```
https://restapi.amap.com/v3/geocode/geo?address={位置}&output=JSON&key={用户的key}
```
**执行 curl 请求:**
```bash
curl -s "https://restapi.amap.com/v3/geocode/geo?address={位置}&output=JSON&key={用户的key}"
```
**API 返回示例:**
```json
{
"status": "1",
"info": "OK",
"geocodes": [
{
"formatted_address": "北京市西城区西直门",
"location": "116.353138,39.939385"
}
]
}
```
从返回结果中提取 `geocodes[0].location`,格式为 `经度,纬度`(如 `116.353138,39.939385`),拆分为:
- **经度(longitude)**:`116.353138`
- **纬度(latitude)**:`39.939385`
#### 第四步:拼接带坐标的搜索链接
**URL 格式:**
```
https://ditu.amap.com/search?query={搜索类别}&query_type=RQBXY&longitude={经度}&latitude={纬度}&range=1000
```
- **域名**:`ditu.amap.com`
- **路由**:`/search`
- **参数**:
- `query` = 搜索类别(如"美食")
- `query_type` = `RQBXY`(基于坐标的搜索类型)
- `longitude` = 经度
- `latitude` = 纬度
- `range` = 搜索范围(单位:米,默认 1000)
#### 第五步:返回链接给用户
### 完整示例
**用户输入:** "搜索西直门周边美食"
1. 解析:位置 = `西直门`,搜索类别 = `美食`
2. 调用地理编码 API:`curl -s "https://restapi.amap.com/v3/geocode/geo?address=西直门&output=JSON&key=xxx"`
3. 获取坐标:`116.353138,39.939385` → 经度 `116.353138`,纬度 `39.939385`
4. 拼接链接:`https://ditu.amap.com/search?query=美食&query_type=RQBXY&longitude=116.353138&latitude=39.939385&range=1000`
### 回复模板
```
📍 已查询到「{位置}」的坐标({经度},{纬度}),为你生成周边{搜索类别}的搜索链接:
https://ditu.amap.com/search?query={搜索类别}&query_type=RQBXY&longitude={经度}&latitude={纬度}&range=1000
点击链接即可查看「{位置}」周边 1 公里内的{搜索类别}。
```
---
## 场景三:热力图展示
用户有一份包含地理坐标的数据,希望在地图上以热力图的形式可视化展示。
### 触发条件
用户提到"热力图"、"数据可视化"、"地图上展示数据"等意图,并提供了数据地址。
### URL 格式
```
http://a.amap.com/jsapi_demo_show/static/openclaw/heatmap.html?mapStyle={地图风格}&dataUrl={数据地址(URL编码)}
```
- **域名**:`a.amap.com`
- **路由**:`/jsapi_demo_show/static/openclaw/heatmap.html`
- **必填参数**:
- `dataUrl` = 用户数据的 URL 地址(**必须进行 URL 编码**)
- `mapStyle` = 地图风格,可选值:
- `grey` — 暗黑地图模式(深色背景,适合展示亮色热力点)
- `light` — 浅色模式(浅色背景,适合日常查看)
### 执行步骤
1. **发送埋点统计请求**:在执行操作前,发送以下请求进行埋点统计:
```bash
curl -s "https://restapi.amap.com/v3/log/init?eventId=skill.call&product=skill_openclaw&platform=JS&label=heatmap&value=call"
2. **获取数据地址**:从用户输入中提取数据 URL,如果用户未提供,提示用户给出数据地址
3. **确认地图风格**:询问用户偏好的地图风格(`grey` 或 `light`),如果用户未指定,默认使用 `grey`
4. **URL 编码**:将数据地址进行 URL 编码(将 `://` → `%3A%2F%2F`,`/` → `%2F` 等)
5. **拼接链接**:生成完整的热力图 URL
6. **返回链接给用户**
### 示例
**用户输入:** "帮我用这份数据生成热力图:`https://a.amap.com/Loca/static/loca-v2/demos/mock_data/hz_house_order.json`,用暗黑模式"
1. 数据地址:`https://a.amap.com/Loca/static/loca-v2/demos/mock_data/hz_house_order.json`
2. 地图风格:`grey`
3. URL 编码后的数据地址:`https%3A%2F%2Fa.amap.com%2FLoca%2Fstatic%2Floca-v2%2Fdemos%2Fmock_data%2Fhz_house_order.json`
4. 最终链接:
```
http://a.amap.com/jsapi_demo_show/static/openclaw/heatmap.html?mapStyle=grey&dataUrl=https%3A%2F%2Fa.amap.com%2FLoca%2Fstatic%2Floca-v2%2Fdemos%2Fmock_data%2Fhz_house_order.json
```
### 回复模板
```
🔥 已为你生成热力图链接:
http://a.amap.com/jsapi_demo_show/static/openclaw/heatmap.html?mapStyle={地图风格}&dataUrl={编码后的数据地址}
地图风格:{grey/light}
数据来源:{原始数据地址}
点击链接即可查看热力图展示。
```
**请求数据地址的回复模板(用户未提供时):**
```
🔥 生成热力图需要你提供数据地址(JSON 格式的 URL),请给出数据链接。
另外,你希望使用哪种地图风格?
- grey(暗黑模式)
- light(浅色模式)
```
---
## 场景四:POI 详细搜索
使用高德 Web 服务 API 进行更详细的 POI 搜索,支持更多参数和筛选条件。
### 执行步骤
1. **发送埋点统计请求**:在执行操作前,发送以下请求进行埋点统计:
```bash
curl -s "https://restapi.amap.com/v3/log/init?eventId=skill.call&product=skill_openclaw&platform=JS&label=poi-search&value=call"
```
2. **执行 POI 搜索**:根据用户需求调用搜索脚本。
### 使用方法
```bash
# 基础搜索
node scripts/poi-search.js --keywords=肯德基 --city=北京
# 搜索更多结果
node scripts/poi-search.js --keywords=餐厅 --city=上海 --page=1 --offset=20
# 周边搜索(需要提供中心点坐标和搜索半径)
node scripts/poi-search.js --keywords=酒店 --location=116.397428,39.90923 --radius=1000
```
### 参数说明
| 参数 | 说明 | 必填 | 示例 |
|------|------|------|------|
| `--keywords` | 搜索关键词 | 是 | `--keywords=肯德基` |
| `--city` | 城市名称或编码 | 否 | `--city=北京` |
| `--types` | POI 类型编码 | 否 | `--types=050000` |
| `--location` | 中心点坐标(经度,纬度) | 否 | `--location=116.397428,39.90923` |
| `--radius` | 搜索半径(米) | 否 | `--radius=1000` |
| `--page` | 页码 | 否 | `--page=1` |
| `--offset` | 每页数量(最大25) | 否 | `--offset=10` |
### 在代码中使用
```javascript
const { searchPOI } = require('./index');
async function example() {
const result = await searchPOI({
keywords: '咖啡厅',
city: '杭州',
page: 1,
offset: 10
});
if (result && result.pois) {
result.pois.forEach(poi => {
console.log(`poi.name - poi.address`);
});
}
}
example();
```
---
## 场景五:路径规划
规划不同出行方式的路线。
### 执行步骤
1. **发送埋点统计请求**:在执行操作前,发送以下请求进行埋点统计:
```bash
curl -s "https://restapi.amap.com/v3/log/init?eventId=skill.call&product=skill_openclaw&platform=JS&label=route-planning&value=call"
```
2. **执行路径规划**:根据用户需求调用路径规划脚本。
### 使用方法
```bash
# 步行路线
node scripts/route-planning.js --type=walking --origin=116.397428,39.90923 --destination=116.427281,39.903719
# 驾车路线
node scripts/route-planning.js --type=driving --origin=116.397428,39.90923 --destination=116.427281,39.903719
# 公交路线
node scripts/route-planning.js --type=transfer --origin=116.397428,39.90923 --destination=116.427281,39.903719 --city=北京
```
### 路线类型
- `walking` - 步行路线
- `driving` - 驾车路线
- `riding` - 骑行路线
- `transfer` - 公交路线(需要指定城市)
---
## 场景六:智能旅游规划
自动搜索兴趣点并规划游览路线,生成地图可视化链接。
### 执行步骤
1. **发送埋点统计请求**:在执行操作前,发送以下请求进行埋点统计:
```bash
curl -s "https://restapi.amap.com/v3/log/init?eventId=skill.call&product=skill_openclaw&platform=JS&label=travel-planner&value=call"
```
2. **执行旅游规划**:根据用户需求调用旅游规划脚本。
### 使用方法
```bash
# 基础旅游规划
node scripts/travel-planner.js --city=北京 --interests=景点,美食,酒店
# 指定路线类型(walking/driving/riding/transfer)
node scripts/travel-planner.js --city=杭州 --interests=西湖,美食,茶馆 --routeType=walking
# 驾车游览
node scripts/travel-planner.js --city=上海 --interests=外滩,南京路,城隍庙 --routeType=driving
```
### 功能说明
- 自动搜索指定城市的兴趣点(每类最多5个)
- 按顺序规划各兴趣点之间的路线
---
## 场景七:导航与搜索(Python 脚本)
通过 Python 脚本 `gaode_skill.py` 提供导航路线规划和 POI 搜索功能。
### 前置条件
- 已安装 Python 3
### 使用方法
```bash
# 导航路线规划
python gaode_skill.py direction 北京站 天安门
python gaode_skill.py direction 北京站 天安门 driving
python gaode_skill.py direction 116.397428,39.90923 天安门 walking
# POI 搜索
python gaode_skill.py search 北京站周边的川菜
```
### 路线类型
- `driving` - 驾车(默认)
- `walking` - 步行
- `bicycling` - 骑行
---
## 配置管理
配置文件位于 `config.json`(仅所有者可读写,权限 0600),包含以下内容:
> [!WARNING]
> `config.json` 包含 API Key 敏感信息,已通过 `.gitignore` 排除版本控制。请勿手动分享此文件。
```json
{
"webServiceKey": "your_amap_webservice_key_here"
}
```
设置 Key 的方式:
1. **环境变量**:`export AMAP_WEBSERVICE_KEY=your_key`
2. **命令行参数**:`node index.js your_key`
3. **自动提示**:首次运行时自动提示输入
4. **手动编辑**:直接编辑 `config.json` 文件
---
## 注意事项
- **遥测声明**:本 Skill 在每次执行操作前会向高德服务器 (`restapi.amap.com/v3/log/init`) 发送匿名使用统计请求,用于功能调用计数,该请求不包含用户个人信息或 API Key
- **场景判断是关键**:区分用户是"直接搜某个东西"、"在某个位置附近搜某个东西"、"规划路线"还是"旅游规划"
- 关键词应尽量精简准确,提取用户真正想搜的内容
- URL 中的中文关键词浏览器会自动处理编码,无需手动 encode
- 场景二、四、五、六需要用户提供高德 API Key,**必须先获取 Key 后再发起请求**,不能跳过
- 如果地理编码 API 返回 `status` 不为 `"1"`,说明请求失败,需提示用户检查 Key 是否正确或地址是否有效
- API 返回的 `location` 格式为 `经度,纬度`(注意:经度在前,纬度在后)
- 场景二的搜索范围默认 1000 米,用户如有需要可调整 `range` 参数
- 请妥善保管你的 Web Service Key,不要分享给他人
- 高德 Web 服务 API 有调用频率限制,请合理使用
- 免费用户每日调用量有限制,具体请查看高德开放平台说明
## 相关链接
- [高德开放平台](https://lbs.amap.com/)
- [创建应用和获取 Key](https://lbs.amap.com/api/webservice/create-project-and-key)
- [POI 搜索 API 文档](https://lbs.amap.com/api/webservice/guide/api-advanced/newpoisearch)
- [Web 服务 API 总览](https://lbs.amap.com/api/webservice/summary)
FILE:config.example.json
{
"webServiceKey": "your_amap_webservice_key_here"
}
FILE:gaode_skill.py
#!/usr/bin/env python3
"""
高德地图 JSAPI Agent Skill
通过 Unix Domain Socket 与 Electron 桌面应用通信,支持导航和 POI 搜索场景。
用法:
python gaode_skill.py direction 北京站 天安门
python gaode_skill.py direction 北京站 天安门 driving
python gaode_skill.py direction 116.397428,39.90923 天安门 walking
python gaode_skill.py search 北京站周边的川菜
"""
import sys
import json
import socket
import time
import os
SOCKET_PATH = "/tmp/jsapi-electron.sock"
SOCKET_TIMEOUT_SECONDS = 30
VALID_ROUTE_TYPES = {"driving", "walking", "bicycling"}
def send_command(command_payload: dict) -> dict:
"""
连接到 Electron 应用的 Unix Domain Socket,发送命令并等待结果。
Args:
command_payload: 要发送的命令字典,包含 cmd、params、requestId 字段。
Returns:
Electron 应用返回的结果字典。
Raises:
FileNotFoundError: Socket 文件不存在(应用未启动)。
TimeoutError: 等待响应超时。
ConnectionError: 连接或通信失败。
"""
if not os.path.exists(SOCKET_PATH):
raise FileNotFoundError(
f"Socket 文件不存在:{SOCKET_PATH}\n"
"请先启动高德地图 Electron 应用(cd APP/jsapi-electron-app && npm start)"
)
client_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
client_socket.settimeout(SOCKET_TIMEOUT_SECONDS)
try:
client_socket.connect(SOCKET_PATH)
message = json.dumps(command_payload, ensure_ascii=False) + "\n"
client_socket.sendall(message.encode("utf-8"))
# 读取响应(按换行符分割)
response_buffer = ""
while True:
chunk = client_socket.recv(4096)
if not chunk:
break
response_buffer += chunk.decode("utf-8")
if "\n" in response_buffer:
break
response_line = response_buffer.split("\n")[0].strip()
if not response_line:
raise ConnectionError("收到空响应")
return json.loads(response_line)
except socket.timeout:
raise TimeoutError(
f"等待 Electron 应用响应超时({SOCKET_TIMEOUT_SECONDS}s),"
"请确认应用正在运行且地图已加载完成。"
)
except json.JSONDecodeError as error:
raise ConnectionError(f"响应 JSON 解析失败:{error},原始内容:{response_buffer!r}")
finally:
client_socket.close()
def build_request_id() -> str:
"""生成唯一的请求 ID。"""
return f"skill-{int(time.time() * 1000)}"
def format_direction_result(result: dict) -> str:
"""将导航命令的结果格式化为可读文本。"""
if not result.get("success"):
return f"❌ 导航失败:{result.get('error', '未知错误')}"
origin_lnglat = result.get("originLnglat", [])
destination_lnglat = result.get("destinationLnglat", [])
route_type_labels = {"driving": "驾车", "walking": "步行", "bicycling": "骑行"}
route_type = result.get("routeType", "driving")
route_label = route_type_labels.get(route_type, route_type)
lines = [
f"✅ {route_label}路线规划成功",
f"",
f"📍 起点:{result.get('originName', '—')}",
f" 坐标:{origin_lnglat[0]:.6f}, {origin_lnglat[1]:.6f}" if len(origin_lnglat) == 2 else " 坐标:—",
f"🏁 终点:{result.get('destinationName', '—')}",
f" 坐标:{destination_lnglat[0]:.6f}, {destination_lnglat[1]:.6f}" if len(destination_lnglat) == 2 else " 坐标:—",
f"",
f"🗺️ 路线已在地图上展示。",
]
return "\n".join(lines)
def format_search_result(result: dict) -> str:
"""将搜索命令的结果格式化为可读文本(带序号,方便大模型继续选择)。"""
if not result.get("success"):
return f"❌ 搜索失败:{result.get('error', '未知错误')}"
pois = result.get("pois", [])
total = result.get("total", 0)
keywords = result.get("params", {}).get("keywords", "")
if total == 0:
return f"🔍 搜索「{keywords}」未找到相关结果。"
lines = [
f"🔍 搜索「{keywords}」,共找到 {total} 个结果:",
f"",
]
for poi in pois:
index = poi.get("index", "?")
name = poi.get("name", "—")
address = poi.get("address") or "暂无地址"
poi_type = poi.get("type", "").split(";")[0] if poi.get("type") else ""
location = poi.get("location", "")
lines.append(f"{index}. {name}")
lines.append(f" 📌 {address}")
if poi_type:
lines.append(f" 🏷️ {poi_type}")
if location:
lines.append(f" 🌐 {location}")
lines.append("")
lines.append("💡 POI 已在地图上标注,可点击查看详情。")
return "\n".join(lines)
def run_direction(origin: str, destination: str, route_type: str = "driving") -> None:
"""
执行导航场景:解析起终点并在地图上展示路线。
Args:
origin: 起点,可以是地名或坐标(格式:经度,纬度)。
destination: 终点,可以是地名或坐标(格式:经度,纬度)。
route_type: 路线类型,driving / walking / bicycling,默认 driving。
"""
if route_type not in VALID_ROUTE_TYPES:
print(f"⚠️ 不支持的路线类型「{route_type}」,已自动切换为 driving。")
route_type = "driving"
payload = {
"cmd": "direction",
"requestId": build_request_id(),
"params": {
"origin": origin,
"destination": destination,
"type": route_type,
},
}
print(f"🚀 发送导航指令:{origin} → {destination}({route_type})")
result = send_command(payload)
print(format_direction_result(result))
def run_search(keywords: str) -> None:
"""
执行搜索场景:在地图上展示 POI 搜索结果。
Args:
keywords: 搜索关键词,例如「北京站周边的川菜」。
"""
payload = {
"cmd": "search",
"requestId": build_request_id(),
"params": {
"keywords": keywords,
},
}
print(f"🔍 发送搜索指令:{keywords}")
result = send_command(payload)
print(format_search_result(result))
def print_usage() -> None:
"""打印使用说明。"""
usage = """
高德地图 JSAPI Agent Skill
用法:
python gaode_skill.py direction <起点> <终点> [路线类型]
python gaode_skill.py search <搜索关键词>
路线类型(可选,默认 driving):
driving 驾车
walking 步行
bicycling 骑行
示例:
python gaode_skill.py direction 北京站 天安门
python gaode_skill.py direction 北京站 天安门 driving
python gaode_skill.py direction 116.397428,39.90923 天安门 walking
python gaode_skill.py search 北京站周边的川菜
注意:
- 起点/终点可以是地名,也可以是「经度,纬度」格式的坐标
- 使用前请确保 Electron 应用已启动并加载完成
""".strip()
print(usage)
def main() -> None:
args = sys.argv[1:]
if not args or args[0] in ("-h", "--help"):
print_usage()
sys.exit(0)
command = args[0].lower()
try:
if command == "direction":
if len(args) < 3:
print("❌ direction 命令需要提供起点和终点。")
print(" 示例:python gaode_skill.py direction 北京站 天安门")
sys.exit(1)
origin = args[1]
destination = args[2]
route_type = args[3].lower() if len(args) >= 4 else "driving"
run_direction(origin, destination, route_type)
elif command == "search":
if len(args) < 2:
print("❌ search 命令需要提供搜索关键词。")
print(" 示例:python gaode_skill.py search 北京站周边的川菜")
sys.exit(1)
# 支持多个词拼接为完整关键词
keywords = " ".join(args[1:])
run_search(keywords)
else:
print(f"❌ 未知命令:{command}")
print(" 支持的命令:direction、search")
print(" 使用 -h 查看帮助。")
sys.exit(1)
except FileNotFoundError as error:
print(f"❌ {error}")
sys.exit(1)
except TimeoutError as error:
print(f"⏱️ {error}")
sys.exit(1)
except ConnectionError as error:
print(f"🔌 连接错误:{error}")
sys.exit(1)
except KeyboardInterrupt:
print("\n已取消。")
sys.exit(0)
if __name__ == "__main__":
main()
FILE:index.js
const fs = require('fs');
const path = require('path');
const axios = require('axios');
// 配置文件路径
const CONFIG_FILE = path.join(__dirname, 'config.json');
/**
* 读取配置文件
*/
function readConfig() {
try {
if (fs.existsSync(CONFIG_FILE)) {
const data = fs.readFileSync(CONFIG_FILE, 'utf8');
return JSON.parse(data);
}
} catch (error) {
console.error('读取配置文件失败:', error.message);
}
return {};
}
/**
* 保存配置文件
*/
function saveConfig(config) {
try {
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf8');
// 设置文件权限为仅所有者可读写,防止密钥泄露
fs.chmodSync(CONFIG_FILE, 0o600);
console.log('配置已保存到:', CONFIG_FILE);
return true;
} catch (error) {
console.error('保存配置文件失败:', error.message);
return false;
}
}
/**
* 获取高德 Web Service Key
*/
function getWebServiceKey() {
const config = readConfig();
return config.webServiceKey || null;
}
/**
* 设置高德 Web Service Key
*/
function setWebServiceKey(key) {
const config = readConfig();
config.webServiceKey = key;
return saveConfig(config);
}
/**
* 检查并提示用户输入 Key
*/
async function ensureWebServiceKey() {
// 优先从环境变量读取
let key = process.env.AMAP_WEBSERVICE_KEY;
if (!key && process.env.AMAP_KEY) {
key = process.env.AMAP_KEY;
console.warn('⚠️ 环境变量 AMAP_KEY 已废弃,请迁移到 AMAP_WEBSERVICE_KEY');
}
if (!key) {
// 尝试从配置文件读取
key = getWebServiceKey();
}
if (!key) {
console.log('\n⚠️ 未找到高德 Web Service Key');
console.log('请访问以下地址创建应用并获取 Key:');
console.log('https://lbs.amap.com/api/webservice/create-project-and-key\n');
throw new Error('请设置环境变量 AMAP_WEBSERVICE_KEY 或提供高德 Web Service Key');
}
return key;
}
/**
* POI 搜索
* @param {Object} params - 搜索参数
* @param {string} params.keywords - 查询关键字
* @param {string} params.city - 城市名称或城市编码
* @param {string} params.types - POI类型编码
* @param {string} params.location - 中心点坐标
* @param {number} params.radius - 搜索半径(米)
* @param {number} params.page - 当前页数
* @param {number} params.offset - 每页记录数
*/
async function searchPOI(params) {
const key = await ensureWebServiceKey();
const url = 'https://restapi.amap.com/v5/place/text';
const requestParams = {
key: key,
keywords: params.keywords || '',
region: params.city || '',
city_limit: params.cityLimit !== false,
...params
};
try {
console.log('🔍 正在搜索 POI...');
const response = await axios.get(url, { params: requestParams });
if (response.data.status === '1') {
console.log(`✅ 搜索成功,共找到 response.data.count 条结果\n`);
return response.data;
} else {
console.error('❌ 搜索失败:', response.data.info);
return null;
}
} catch (error) {
console.error('❌ 请求失败:', error.message);
return null;
}
}
/**
* 步行路径规划
* @param {Object} params - 规划参数
* @param {string} params.origin - 起点坐标 "经度,纬度"
* @param {string} params.destination - 终点坐标 "经度,纬度"
*/
async function walkingRoute(params) {
const key = await ensureWebServiceKey();
const url = 'https://restapi.amap.com/v3/direction/walking';
const requestParams = {
key: key,
origin: params.origin,
destination: params.destination
};
try {
console.log('🚶 正在规划步行路线...');
const response = await axios.get(url, { params: requestParams });
if (response.data.status === '1') {
console.log('✅ 步行路线规划成功\n');
return response.data;
} else {
console.error('❌ 步行路线规划失败:', response.data.info);
return null;
}
} catch (error) {
console.error('❌ 请求失败:', error.message);
return null;
}
}
/**
* 驾车路径规划
* @param {Object} params - 规划参数
* @param {string} params.origin - 起点坐标 "经度,纬度"
* @param {string} params.destination - 终点坐标 "经度,纬度"
* @param {string} params.waypoints - 途经点坐标,多个用;分隔
* @param {number} params.strategy - 驾车策略,默认10
*/
async function drivingRoute(params) {
const key = await ensureWebServiceKey();
const url = 'https://restapi.amap.com/v3/direction/driving';
const requestParams = {
key: key,
origin: params.origin,
destination: params.destination,
strategy: params.strategy || 10,
extensions: 'base'
};
if (params.waypoints) {
requestParams.waypoints = params.waypoints;
}
try {
console.log('🚗 正在规划驾车路线...');
const response = await axios.get(url, { params: requestParams });
if (response.data.status === '1') {
console.log('✅ 驾车路线规划成功\n');
return response.data;
} else {
console.error('❌ 驾车路线规划失败:', response.data.info);
return null;
}
} catch (error) {
console.error('❌ 请求失败:', error.message);
return null;
}
}
/**
* 骑行路径规划
* @param {Object} params - 规划参数
* @param {string} params.origin - 起点坐标 "经度,纬度"
* @param {string} params.destination - 终点坐标 "经度,纬度"
*/
async function ridingRoute(params) {
const key = await ensureWebServiceKey();
const url = 'https://restapi.amap.com/v4/direction/bicycling';
const requestParams = {
key: key,
origin: params.origin,
destination: params.destination
};
try {
console.log('🚴 正在规划骑行路线...');
const response = await axios.get(url, { params: requestParams });
if (response.data.errcode === 0) {
console.log('✅ 骑行路线规划成功\n');
return response.data;
} else {
console.error('❌ 骑行路线规划失败:', response.data.errmsg);
return null;
}
} catch (error) {
console.error('❌ 请求失败:', error.message);
return null;
}
}
/**
* 公交路径规划
* @param {Object} params - 规划参数
* @param {string} params.origin - 起点坐标 "经度,纬度"
* @param {string} params.destination - 终点坐标 "经度,纬度"
* @param {string} params.city - 城市名称或城市编码
* @param {number} params.strategy - 公交策略,默认0(最快捷)
* @param {boolean} params.nightflag - 是否计算夜班车,默认false
*/
async function transitRoute(params) {
const key = await ensureWebServiceKey();
const url = 'https://restapi.amap.com/v3/direction/transit/integrated';
const requestParams = {
key: key,
origin: params.origin,
destination: params.destination,
city: params.city,
strategy: params.strategy || 0,
nightflag: params.nightflag ? 1 : 0
};
try {
console.log('🚌 正在规划公交路线...');
const response = await axios.get(url, { params: requestParams });
if (response.data.status === '1') {
console.log('✅ 公交路线规划成功\n');
return response.data;
} else {
console.error('❌ 公交路线规划失败:', response.data.info);
return null;
}
} catch (error) {
console.error('❌ 请求失败:', error.message);
return null;
}
}
/**
* 生成地图可视化链接
* @param {Array} mapTaskData - 地图任务数据数组
* @returns {string} 可视化链接
*/
function generateMapLink(mapTaskData) {
const baseUrl = 'https://a.amap.com/jsapi_demo_show/static/openclaw/travel_plan.html';
const dataStr = encodeURIComponent(JSON.stringify(mapTaskData));
return `baseUrl?data=dataStr`;
}
/**
* 旅游规划助手
* @param {Object} params - 规划参数
* @param {string} params.city - 城市名称
* @param {Array<string>} params.interests - 兴趣点关键词数组,如 ['景点', '美食', '酒店']
* @param {string} params.routeType - 路线类型:driving/walking/riding/transfer
* @returns {Object} 包含 pois、mapTaskData、mapLink 和 htmlLink
*/
async function travelPlanner(params) {
const { city, interests = [], routeType = 'walking' } = params;
console.log(`\n🗺️ 开始为您规划 city 的旅游行程...\n`);
const mapTaskData = [];
const poiResults = [];
// 搜索各类兴趣点
for (const interest of interests) {
console.log(`📍 搜索 interest...`);
const result = await searchPOI({
keywords: interest,
city: city,
page: 1,
offset: 5
});
if (result && result.pois && result.pois.length > 0) {
poiResults.push(...result.pois);
// 添加到地图数据 - 严格按照 PoiTask 接口格式
result.pois.forEach(poi => {
const [lng, lat] = poi.location.split(',').map(Number);
mapTaskData.push({
type: 'poi',
lnglat: [lng, lat],
sort: poi.type || interest,
text: poi.name,
remark: poi.address || `interest推荐`
});
});
}
}
// 如果有多个POI,规划路线
if (poiResults.length >= 2) {
console.log(`\n🛣️ 规划游览路线(routeType)...\n`);
for (let i = 0; i < poiResults.length - 1; i++) {
const start = poiResults[i];
const end = poiResults[i + 1];
const [startLng, startLat] = start.location.split(',').map(Number);
const [endLng, endLat] = end.location.split(',').map(Number);
// 添加路线到地图数据 - 严格按照 RouteTask 接口格式
const routeTask = {
type: 'route',
routeType: routeType,
start: [startLng, startLat],
end: [endLng, endLat],
remark: `从 start.name 到 end.name`
};
// 如果是公交路线,添加 city 参数
if (routeType === 'transfer') {
routeTask.city = city;
}
mapTaskData.push(routeTask);
}
}
console.log('\n✅ 旅游规划完成!\n');
console.log('📍 推荐地点:');
poiResults.forEach((poi, index) => {
console.log(`index + 1. poi.name`);
console.log(` 地址: poi.address`);
console.log(` 类型: poi.type\n`);
});
return {
pois: poiResults,
};
}
// 导出函数供其他脚本使用
module.exports = {
readConfig,
saveConfig,
getWebServiceKey,
setWebServiceKey,
ensureWebServiceKey,
searchPOI,
walkingRoute,
drivingRoute,
ridingRoute,
transitRoute,
generateMapLink,
travelPlanner
};
// 如果直接运行此文件,执行示例搜索
if (require.main === module) {
(async () => {
try {
// 示例:搜索北京的肯德基
const result = await searchPOI({
keywords: '肯德基',
city: '北京',
page: 1,
offset: 10
});
if (result && result.pois) {
console.log('搜索结果:');
result.pois.forEach((poi, index) => {
console.log(`index + 1. poi.name`);
console.log(` 地址: poi.address`);
console.log(` 类型: poi.type`);
console.log(` 坐标: poi.location\n`);
});
}
} catch (error) {
console.error('执行失败:', error.message);
process.exit(1);
}
})();
}
FILE:package.json
{
"name": "amap-webservice",
"version": "1.0.0",
"description": "高德Web服务API向开发者提供HTTP接口,开发者可通过这些接口使用各类型的地理数据服务,返回结果支持JSON和XML格式。",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"amap",
"webservice",
"poi",
"geocoding"
],
"author": "",
"license": "MIT",
"dependencies": {
"axios": "^1.13.6"
}
}
FILE:scripts/poi-search.js
#!/usr/bin/env node
/**
* POI 搜索脚本
* 使用方法:
* node scripts/poi-search.js --keywords=肯德基 --city=北京
* 或设置环境变量: AMAP_WEBSERVICE_KEY=your_key node scripts/poi-search.js --keywords=肯德基
*/
const { searchPOI } = require('../index');
// 解析命令行参数
function parseArgs() {
const args = {};
process.argv.slice(2).forEach(arg => {
if (arg.startsWith('--')) {
const [key, value] = arg.slice(2).split('=');
args[key] = value;
}
});
return args;
}
// 主函数
async function main() {
const args = parseArgs();
// 检查必需参数
if (!args.keywords) {
console.error('❌ 缺少必需参数: --keywords');
console.log('\n使用方法:');
console.log('node scripts/poi-search.js --keywords=关键词 [--city=城市] [--types=类型] [--page=页码] [--offset=每页数量]');
console.log('\n示例:');
console.log('node scripts/poi-search.js --keywords=肯德基 --city=北京 --page=1 --offset=20');
process.exit(1);
}
// 检查是否设置了 AMAP_WEBSERVICE_KEY(向后兼容 AMAP_KEY)
if (!process.env.AMAP_WEBSERVICE_KEY && !process.env.AMAP_KEY) {
console.error('❌ 请设置环境变量 AMAP_WEBSERVICE_KEY');
console.log('\n示例:');
console.log('export AMAP_WEBSERVICE_KEY=your_amap_key');
process.exit(1);
}
if (!process.env.AMAP_WEBSERVICE_KEY && process.env.AMAP_KEY) {
console.warn('⚠️ 环境变量 AMAP_KEY 已废弃,请迁移到 AMAP_WEBSERVICE_KEY');
}
// 构建搜索参数
const params = {
keywords: args.keywords,
city: args.city || '',
types: args.types || '',
page: parseInt(args.page) || 1,
offset: parseInt(args.offset) || 10
};
// 可选参数
if (args.location) params.location = args.location;
if (args.radius) params.radius = parseInt(args.radius);
if (args.cityLimit !== undefined) params.cityLimit = args.cityLimit === 'true';
try {
const result = await searchPOI(params);
if (result && result.pois && result.pois.length > 0) {
console.log(`\n📍 共找到 result.count 条结果,当前显示第 params.page 页:\n`);
console.log('='.repeat(80));
result.pois.forEach((poi, index) => {
const num = (params.page - 1) * params.offset + index + 1;
console.log(`\nnum. poi.name`);
console.log(` 📍 地址: poi.address || '无'`);
console.log(` 🏷️ 类型: poi.type`);
console.log(` 📞 电话: poi.tel || '无'`);
console.log(` 🗺️ 坐标: poi.location`);
if (poi.distance) {
console.log(` 📏 距离: poi.distance米`);
}
});
console.log('\n' + '='.repeat(80));
// 输出分页信息
const totalPages = Math.ceil(result.count / params.offset);
console.log(`\n第 params.page/totalPages 页`);
if (params.page < totalPages) {
console.log(`\n💡 查看下一页: node scripts/poi-search.js --keywords=params.keywords --city=params.city --page=params.page + 1`);
}
} else {
console.log('\n❌ 未找到相关结果');
}
} catch (error) {
console.error('\n❌ 执行失败:', error.message);
process.exit(1);
}
}
// 执行主函数
main();
FILE:scripts/route-planning.js
#!/usr/bin/env node
/**
* 路径规划脚本
* 使用方法:
* node scripts/route-planning.js --type=walking --origin=116.397428,39.90923 --destination=116.427281,39.903719
*/
const { walkingRoute, drivingRoute, ridingRoute, transitRoute, generateMapLink } = require('../index');
// 解析命令行参数
function parseArgs() {
const args = {};
process.argv.slice(2).forEach(arg => {
if (arg.startsWith('--')) {
const [key, value] = arg.slice(2).split('=');
args[key] = value;
}
});
return args;
}
// 主函数
async function main() {
const args = parseArgs();
// 检查必需参数
if (!args.type || !args.origin || !args.destination) {
console.error('❌ 缺少必需参数');
console.log('\n使用方法:');
console.log('node scripts/route-planning.js --type=路线类型 --origin=起点坐标 --destination=终点坐标 [其他参数]');
console.log('\n路线类型:');
console.log(' walking - 步行');
console.log(' driving - 驾车');
console.log(' riding - 骑行');
console.log(' transfer - 公交(需要额外提供 --city 参数)');
console.log('\n示例:');
console.log('# 步行路线');
console.log('node scripts/route-planning.js --type=walking --origin=116.397428,39.90923 --destination=116.427281,39.903719');
console.log('\n# 驾车路线(带途经点)');
console.log('node scripts/route-planning.js --type=driving --origin=116.397428,39.90923 --destination=116.427281,39.903719 --waypoints=116.410000,39.910000');
console.log('\n# 公交路线');
console.log('node scripts/route-planning.js --type=transfer --origin=116.397428,39.90923 --destination=116.427281,39.903719 --city=北京');
process.exit(1);
}
const { type, origin, destination } = args;
try {
let result = null;
let mapTaskData = [];
// 解析起点和终点坐标
const [originLng, originLat] = origin.split(',').map(Number);
const [destLng, destLat] = destination.split(',').map(Number);
// 根据类型调用不同的路径规划API
switch (type) {
case 'walking':
result = await walkingRoute({ origin, destination });
if (result && result.route) {
mapTaskData.push({
type: 'route',
routeType: 'walking',
start: [originLng, originLat],
end: [destLng, destLat],
remark: `步行路线,距离约 (result.route.paths[0].distance / 1000).toFixed(2) 公里`
});
console.log('📊 路线信息:');
console.log(` 距离: (result.route.paths[0].distance / 1000).toFixed(2) 公里`);
console.log(` 预计时间: Math.round(result.route.paths[0].duration / 60) 分钟\n`);
}
break;
case 'driving':
const drivingParams = { origin, destination };
if (args.waypoints) {
drivingParams.waypoints = args.waypoints;
}
if (args.strategy) {
drivingParams.strategy = parseInt(args.strategy);
}
result = await drivingRoute(drivingParams);
if (result && result.route) {
const path = result.route.paths[0];
mapTaskData.push({
type: 'route',
routeType: 'driving',
start: [originLng, originLat],
end: [destLng, destLat],
remark: `驾车路线,距离约 (path.distance / 1000).toFixed(2) 公里`
});
console.log('📊 路线信息:');
console.log(` 距离: (path.distance / 1000).toFixed(2) 公里`);
console.log(` 预计时间: Math.round(path.duration / 60) 分钟`);
console.log(` 过路费: path.tolls || 0 元`);
console.log(` 红绿灯: path.traffic_lights || 0 个\n`);
}
break;
case 'riding':
result = await ridingRoute({ origin, destination });
if (result && result.data) {
const path = result.data.paths[0];
mapTaskData.push({
type: 'route',
routeType: 'riding',
start: [originLng, originLat],
end: [destLng, destLat],
remark: `骑行路线,距离约 (path.distance / 1000).toFixed(2) 公里`
});
console.log('📊 路线信息:');
console.log(` 距离: (path.distance / 1000).toFixed(2) 公里`);
console.log(` 预计时间: Math.round(path.duration / 60) 分钟\n`);
}
break;
case 'transfer':
if (!args.city) {
console.error('❌ 公交路线规划需要提供 --city 参数');
process.exit(1);
}
const transitParams = {
origin,
destination,
city: args.city,
strategy: args.strategy ? parseInt(args.strategy) : 0,
nightflag: args.nightflag === 'true'
};
result = await transitRoute(transitParams);
if (result && result.route) {
mapTaskData.push({
type: 'route',
routeType: 'transfer',
start: [originLng, originLat],
end: [destLng, destLat],
city: args.city,
remark: `公交路线,共 result.route.transits.length 个方案`
});
console.log('📊 路线信息:');
console.log(` 方案数量: result.route.transits.length 个`);
if (result.route.transits.length > 0) {
const transit = result.route.transits[0];
console.log(` 预计时间: Math.round(transit.duration / 60) 分钟`);
console.log(` 费用: transit.cost 元`);
console.log(` 步行距离: transit.walking_distance 米\n`);
}
}
break;
default:
console.error(`❌ 不支持的路线类型: type`);
process.exit(1);
}
if (result && mapTaskData.length > 0) {
// 生成地图链接
const mapLink = generateMapLink(mapTaskData);
console.log('🗺️ 地图可视化链接:');
console.log(mapLink);
console.log('\n💡 提示: 复制链接到浏览器打开即可查看路线详情\n');
} else {
console.log('\n❌ 路线规划失败,请检查参数是否正确');
}
} catch (error) {
console.error('\n❌ 执行失败:', error.message);
process.exit(1);
}
}
// 执行主函数
main();
FILE:scripts/travel-planner.js
#!/usr/bin/env node
/**
* 旅游规划脚本
* 使用方法:
* node scripts/travel-planner.js --city=北京 --interests=景点,美食,酒店 --routeType=walking
*/
const { travelPlanner } = require('../index');
// 解析命令行参数
function parseArgs() {
const args = {};
process.argv.slice(2).forEach(arg => {
if (arg.startsWith('--')) {
const [key, value] = arg.slice(2).split('=');
args[key] = value;
}
});
return args;
}
// 主函数
async function main() {
const args = parseArgs();
// 检查必需参数
if (!args.city) {
console.error('❌ 缺少必需参数: --city');
console.log('\n使用方法:');
console.log('node scripts/travel-planner.js --city=城市名 [--interests=兴趣点1,兴趣点2] [--routeType=路线类型]');
console.log('\n示例:');
console.log('node scripts/travel-planner.js --city=北京 --interests=景点,美食,酒店 --routeType=walking');
console.log('\n路线类型选项:');
console.log(' walking - 步行(默认)');
console.log(' driving - 驾车');
console.log(' riding - 骑行');
console.log(' transfer - 公交');
process.exit(1);
}
// 解析兴趣点
const interests = args.interests ? args.interests.split(',') : ['景点', '美食'];
const routeType = args.routeType || 'walking';
// 验证路线类型
const validRouteTypes = ['walking', 'driving', 'riding', 'transfer'];
if (!validRouteTypes.includes(routeType)) {
console.error(`❌ 无效的路线类型: routeType`);
console.log('有效的路线类型:', validRouteTypes.join(', '));
process.exit(1);
}
try {
const result = await travelPlanner({
city: args.city,
interests: interests,
routeType: routeType
});
if (result && result.pois.length > 0) {
console.log('═'.repeat(80));
console.log('\n📊 规划数据统计:');
console.log(` 兴趣点数量: result.pois.length 个`);
console.log(` 路线数量: result.mapTaskData.filter(item => item.type === 'route').length 条`);
console.log(` 出行方式: routeType === 'driving' ? '驾车' : routeType === 'riding' ? '骑行' : '公交'`);
console.log('\n' + '═'.repeat(80));
console.log('\n🎉 规划完成!\n');
console.log('📋 数据格式符合 MapTaskData 接口规范');
console.log(' - PoiTask: 兴趣点任务');
console.log(' - RouteTask: 路线规划任务\n');
} else {
console.log('\n❌ 未找到相关地点,请尝试更换关键词或城市。');
}
} catch (error) {
console.error('\n❌ 执行失败:', error.message);
process.exit(1);
}
}
// 执行主函数
main();
高德地图 JSAPI v2.0 (WebGL) 开发技能。涵盖地图生命周期管理、强制安全配置、3D 视图控制、覆盖物绘制及 LBS 服务集成。
---
name: amap-jsapi-skill
display_name: Gaode Map JSAPI - 高德官方 JavaScript SDK Skill
description: 高德地图 JSAPI v2.0 (WebGL) 开发技能。涵盖地图生命周期管理、强制安全配置、3D 视图控制、覆盖物绘制及 LBS 服务集成。
license: MIT
version: 1.1.1
homepage: https://lbs.amap.com
metadata:
openclaw:
requires:
env:
- AMAP_JSAPI_KEY
- AMAP_SECURITY_JS_CODE
primaryEnv: AMAP_JSAPI_KEY
---
# 高德地图 JSAPI v2.0 开发技能
本指南包含地图初始化、覆盖物、事件、图层等核心模块的 API 说明和代码示例,旨在帮助开发者快速集成高德地图并遵循正确的使用方式。
## 快速开始
### 1. 引入加载器
使用 script 标签加载 loader.js:
```bash
<script src="https://webapi.amap.com/loader.js"></script>
```
### 2. 安全密钥配置 (强制)
**重要**:自 v2.0 起,必须在加载地图前配置安全密钥,否则无法通过鉴权。详情及后端代理示例请参考 [安全策略](references/security.md)。
> **安全提示**:安全密钥属于敏感凭据,请通过环境变量 `AMAP_SECURITY_JS_CODE` 传入,禁止在代码中硬编码。生产环境务必使用 `serviceHost` 代理方式,避免前端暴露密钥。
```javascript
// 在调用 AMapLoader.load 前执行
window._AMapSecurityConfig = {
securityJsCode: process.env.AMAP_SECURITY_JS_CODE, // 通过环境变量安全获取
// serviceHost: 'https://your-proxy-domain/_AMapService', // 生产环境:建议使用代理转发
};
```
### 3. 初始化地图
```javascript
import AMapLoader from '@amap/amap-jsapi-loader';
AMapLoader.load({
key: '您的Web端开发者Key', // 必填
version: '2.0', // 指定版本
plugins: ['AMap.Scale', 'AMap.ToolBar'] // 预加载插件
}).then((AMap) => {
// 可选:设置应用标识,用于 API 调用来源统计
AMap.getConfig().appname = 'amap-jsapi-skill';
const map = new AMap.Map('container', {
viewMode: '3D', // 开启3D视图
zoom: 11, // 初始缩放级别
center: [116.39, 39.90] // 初始中心点
});
map.addControl(new AMap.Scale());
}).catch(e => console.error(e));
```
## 场景示例
### 地图控制
- **生命周期**:`references/map-init.md` - 掌握 `load`、`Map` 实例创建及 `destroy` 销毁流程。
- **视图交互**:`references/view-control.md` - 控制 `zoom` (缩放)、`center` (平移)、`pitch` (俯仰)、`rotation` (旋转)。
### 覆盖物绘制
- **点标记**:`references/marker.md` - 使用 `Marker` (基础)、`LabelMarker` (海量避让) 标注位置。
- **矢量图形**:`references/vector-graphics.md` - 绘制 `Polyline` (轨迹、线)、`Polygon` (区域、面)、`Circle` (范围、圆)。
- **信息展示**:`references/info-window.md` - 通过 `InfoWindow` 展示详细信息。
- **右键菜单**:`references/context-menu.md` - 自定义地图或覆盖物的右键交互。
### 图层管理
- **基础图层**:`references/layers.md` - 标准、卫星、路网及 3D 楼块图层。
- **自有数据**:`references/custom-layers.md` - 集成 `Canvas`、`WMS/WMTS`, `GLCustomLayer` 地图上叠加 Canvas、WMS图层、 Threejs图层。
### 服务与插件
- **LBS 服务**:
- `references/geocoder.md` - 地理编码/逆地理编码(地址/坐标互转)。
- `references/routing.md` - 路径规划(驾车/步行/公交)。
- `references/search.md` - POI 搜索与输入提示。
- **事件系统**:`references/events.md` - 响应点击、拖拽、缩放等交互事件。
## 最佳实践
1. **安全第一**:生产环境务必使用代理服务器转发 `serviceHost`,避免 `securityJsCode` 泄露。
2. **按需加载**:仅在 `plugins` 中声明需要的插件,减少首屏资源体积。
3. **资源释放**:组件卸载时务必调用 `map.destroy()`,防止 WebGL 上下文内存泄漏。
## API Reference
JSAPI 文档分为以下几个类别:
### [Foundation Classes](references/api/foundation.md)
LngLat / Bounds / Pixel / Size
### [Information Window](references/api/info-window.md)
InfoWindow
### [Events](references/api/events.md)
Event
### [Map](references/api/map.md)
Map / MapsEvent
### [Official Layers](references/api/layers-official.md)
TileLayer / Traffic / Satellite / RoadNet / Buildings / DistrictLayer / IndoorMap
### [Standard Layers](references/api/layers-standard.md)
WMS / WMTS / MapboxVectorTileLayer
### [Custom Layers](references/api/layers-custom.md)
HeatMap / VectorLayer / LabelsLayer / CustomLayer / Flexible / ImageLayer / CanvasLayer / GLCustomLayer
### [Markers](references/api/marker.md)
Marker / Text / Icon / LabelMarker / ElasticMarker / MarkerCluster / MassMarks / MoveAnimation / AnimationCallback / EasingCallback
### [Context Menu](references/api/context-menu.md)
ContextMenu
### [Vector Graphics](references/api/vector-graphics.md)
Polygon / Polyline / BezierCurve / Circle / CircleMarker / Ellipse / Rectangle / GeoJSON
### [Overlay Groups](references/api/overlay-group.md)
LayerGroup / OverlayGroup
### [Controls](references/api/controls.md)
Control / Scale / ToolBar / ControlBar / MapType / HawkEye
### [Tools](references/api/tools.md)
RangingTool / MouseTool / PolygonEditor / PolylineEditor / CircleEditor / BezierCurveEditor / EllipseEditor / RectangleEditor
### [Services](references/api/services.md)
WebService / WebServiceCallback
### [Search](references/api/search.md)
AutoComplete / AutoCompleteSearchCallback / PlaceSearch / searchCallback / CloudDataSearch / CloudDataSearchCallback
### [Geocoder](references/api/geocoder.md)
Geocoder / GeocoderCallback / ReGeocoderCallback / convertFrom
### [Routing](references/api/routing.md)
Driving / DrivingCallback / DrivingResult / DriveStepBasic / DriveStepDetail / TruckDriving / Walking / WalkingCallback / WalkingResult / Transfer / TransferCallback / TransferResult / Riding / RidingCallback / RidingResult / DragRoute / DragRouteTruck / GraspRoad / GraspRoadCallback
### [Other Services](references/api/services-other.md)
DistrictSearch / Weather / WeatherLiveResult / WeatherForecastResult / StationSearch / LineSearch
### [Geolocation](references/api/geolocation.md)
Geolocation / GeolocationCallBack / GeolocationResult / CitySearch
### [Common Library](references/api/common.md)
GeometryUtil / DomUtil / Browser / Util
## 使用 skills 必须遵循的规范
1. **校验生成代码可用性**:生成代码后必须进行自我校验,确保代码语法正确、逻辑完整且可以正常运行,禁止输出未经验证的代码。
2. **本地文件放置规范**:所有生成的项目文件必须放置在 openclaw workspace 目录下的 `amap-jsapi/` 文件夹中。文件名统一使用 kebab-case 命名(如 `map-init.html`、`layers-official.html`)。
3. **appname 应用标识(推荐)**:建议在生成地图初始化代码时,在 `AMapLoader.load().then()` 回调中设置应用标识,用于 API 调用来源统计。规则如下:
- **设置位置**:`AMapLoader.load({...}).then((AMap) => {` 回调内部,`new AMap.Map()` 之前
- **设置方式**:`AMap.getConfig().appname = 'amap-jsapi-skill';`
- **代码模板**:
```javascript
AMapLoader.load({
key: '您的Key',
version: '2.0',
plugins: [...]
}).then((AMap) => {
// 可选:设置应用标识,用于 API 调用来源统计
AMap.getConfig().appname = 'amap-jsapi-skill';
const map = new AMap.Map('container', { ... });
});
```
- **说明**:此设置用于标识 API 调用来源,便于统计分析。开发者可根据需要决定是否保留。
## 如何使用
1. 如果有相近的“场景示例”那么去阅读场景示例,再阅读场景示例中的涉及的类的api文档。再结合描述/场景示例/api 去完成任务。
2. 在最终的完成任务前,检查用的api用法是否符合文档。
FILE:_meta.json
{
"ownerId": "kn73td2wbekk991h1j29rjzba982bv3e",
"slug": "amap-jsapi-skill",
"version": "1.0.8",
"publishedAt": 1776393649958
}
FILE:references/api/common.md
## 通用库
一些通用的函数库
## GeometryUtil
### distance
计算两个经纬度点之间的实际距离。单位:米
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
Returns **number**
### distance
计算两个经纬度点之间的实际距离。单位:米
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
Returns **number**
### ringArea
计算一个经纬度路径围成区域的实际面积。单位:平米
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **number**
### ringArea
计算一个经纬度路径围成区域的实际面积。单位:平米
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **number**
### isClockwise
判断一个经纬度路径是否为顺时针
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **boolean**
### isClockwise
判断一个经纬度路径是否为顺时针
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **boolean**
### typePolygon
判断一个经纬度路径面类型
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **boolean**
### typePolygon
判断一个经纬度路径面类型
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **boolean**
### makesureClockwise
将一个路径变为顺时针
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **Array<\[number, number]>**
### makesureClockwise
将一个路径变为顺时针
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **Array<\[number, number]>**
### makesureAntiClockwise
将一个路径变为逆时针
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **Array<\[number, number]>**
### makesureAntiClockwise
将一个路径变为逆时针
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **Array<\[number, number]>**
### distanceOfLine
计算一个经纬度路径的实际长度。单位:米
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **number**
### distanceOfLine
计算一个经纬度路径的实际长度。单位:米
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **number**
### ringRingClip
计算两个经纬度面的交叉区域。只适用于凸多边形
#### Parameters
- `ring1` **Array<LngLatLike>**
- `ring2` **Array<LngLatLike>**
### ringRingClip
计算两个经纬度面的交叉区域。只适用于凸多边形
#### Parameters
- `ring1` **Array<LngLatLike>**
- `ring2` **Array<LngLatLike>**
### doesSegmentsIntersect
判断两个线段是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
- `p4` **LngLatLike**
Returns **boolean**
### doesSegmentsIntersect
判断两个线段是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
- `p4` **LngLatLike**
Returns **boolean**
### doesSegmentLineIntersect
判断线段和一个路径是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `line` **Array<LngLatLike>**
Returns **boolean**
### doesSegmentLineIntersect
判断线段和一个路径是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `line` **Array<LngLatLike>**
Returns **boolean**
### doesSegmentRingIntersect
判断线段和一个环是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### doesSegmentRingIntersect
判断线段和一个环是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### doesSegmentPolygonIntersect
判断线段和多个环是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
Returns **boolean**
### doesSegmentPolygonIntersect
判断线段和多个环是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
Returns **boolean**
### doesLineLineIntersect
判断两个经纬度路径是否相交
#### Parameters
- `line` **Array<LngLatLike>**
- `line` **Array<LngLatLike>**
Returns **boolean**
### doesLineLineIntersect
判断两个经纬度路径是否相交
#### Parameters
- `line` **Array<LngLatLike>**
- `line` **Array<LngLatLike>**
Returns **boolean**
### doesLineRingIntersect
判断经纬度路径和经纬度面是否交叉
#### Parameters
- `line` **Array<LngLatLike>**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### doesLineRingIntersect
判断经纬度路径和经纬度面是否交叉
#### Parameters
- `line` **Array<LngLatLike>**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### doesRingRingIntersect
判断两个经纬度面是否交叉
#### Parameters
- `ring1` **Array<LngLatLike>**
- `ring2` **Array<LngLatLike>**
Returns **boolean**
### doesRingRingIntersect
判断两个经纬度面是否交叉
#### Parameters
- `ring1` **Array<LngLatLike>**
- `ring2` **Array<LngLatLike>**
Returns **boolean**
### pointInRing
判断点是否在环内,支持任意坐标系
#### Parameters
- `p` **LngLatLike**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### pointInRing
判断点是否在环内,支持任意坐标系
#### Parameters
- `p` **LngLatLike**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### isPointInRing
判断点是否在环内
#### Parameters
- `p` **LngLatLike**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### isPointInRing
判断点是否在环内
#### Parameters
- `p` **LngLatLike**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### isPointInBbox
判断点是否在环内
#### Parameters
- `p` **LngLatLike**
- `bbox` **Array<LngLatLike>**
Returns **boolean**
### isPointInBbox
判断点是否在 bbox内
#### Parameters
- `p` **LngLatLike**
- `rect` **Array<LngLatLike>**
Returns **boolean**
### isRingInRing
判断环是否在另一个环内
#### Parameters
- `ring1` **Array<LngLatLike>**
- `ring2` **Array<LngLatLike>**
Returns **boolean**
### isRingInRing
判断环是否在另一个环内
#### Parameters
- `ring1` **Array<LngLatLike>**
- `ring2` **Array<LngLatLike>**
Returns **boolean**
### isPointInPolygon
判断点是否在多个环组成区域内
#### Parameters
- `p` **LngLatLike**
- `rings` **\[Array<ringLngLatLike>]**
Returns **boolean**
### isPointInPolygon
判断点是否在多个环组成区域内
#### Parameters
- `p` **LngLatLike**
- `rings` **\[Array<ringLngLatLike>]**
Returns **boolean**
### isPointInPolygons
判断点是否在带洞多多边型内
#### Parameters
- `p` **LngLatLike**
- `polygons` **\[\[Array<ringLngLatLike>]]**
Returns **boolean**
### isPointOnSegment
判断P1是否在P2P3上,tolerance为误差范围
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
- `tolerance` **Number**
Returns **boolean**
### isPointOnSegment
判断P1是否在P2P3上,tolerance为误差范围
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
- `tolerance` **Number**
Returns **boolean**
### isPointOnLine
判断P是否在line上,tolerance为误差范围
#### Parameters
- `p` **LngLatLike**
- `line` **Array<LngLatLike>**
- `tolerance` **number**
Returns **boolean**
### isPointOnLine
判断P是否在line上,tolerance为误差范围
#### Parameters
- `p` **LngLatLike**
- `line` **Array<LngLatLike>**
- `tolerance` **number**
Returns **boolean**
### isPointOnRing
判断P是否在ring的边上,tolerance为误差范围
#### Parameters
- `p` **LngLatLike**
- `ring` **Array<LngLatLike>**
- `tolerance` **number**
Returns **boolean**
### isPointOnRing
判断P是否在ring的边上,tolerance为误差范围
#### Parameters
- `p` **LngLatLike**
- `ring` **Array<LngLatLike>**
- `tolerance` **number**
Returns **boolean**
### isPointOnPolygon
判断P是否在多个ring的边上,tolerance为误差范围
#### Parameters
- `p` **LngLatLike**
- `tolerance` **number**
Returns **boolean**
### isPointOnPolygon
判断P是否在多个ring的边上,tolerance为误差范围
#### Parameters
- `p` **LngLatLike**
- `tolerance` **number**
Returns **boolean**
### closestOnSegment
计算P2P3上距离P1最近的点
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
Returns **boolean**
### closestOnSegment
计算P2P3上距离P1最近的点
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
Returns **boolean**
### closestOnLine
计算line上距离P最近的点
#### Parameters
- `p` **LngLatLike**
- `line` **Array<LngLatLike>**
Returns **boolean**
### closestOnLine
计算line上距离P最近的点
#### Parameters
- `p` **LngLatLike**
- `line` **Array<LngLatLike>**
Returns **boolean**
### distanceToSegment
计算P2P3到P1的距离。单位:米
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
Returns **LngLat**
### distanceToSegment
计算P2P3到P1的距离。单位:米
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
Returns **LngLat**
### distanceToLine
计算P到line的距离。单位:米
#### Parameters
- `p` **LngLatLike**
- `line` **Array<LngLatLike>**
Returns **number**
### distanceToLine
计算P到line的距离。单位:米
#### Parameters
- `p` **LngLatLike**
- `line` **Array<LngLatLike>**
Returns **number**
## GeometryUtil
GeometryUtil为一组空间数据计算的函数库,v1.4.2新增。支持点线面的空间关系计算、长度、面积计算等等,
### distance
计算两个经纬度点之间的实际距离。单位:米
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
Returns **number**
### distance
计算两个经纬度点之间的实际距离。单位:米
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
Returns **number**
### ringArea
计算一个经纬度路径围成区域的实际面积。单位:平米
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **number**
### ringArea
计算一个经纬度路径围成区域的实际面积。单位:平米
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **number**
### isClockwise
判断一个经纬度路径是否为顺时针
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **boolean**
### isClockwise
判断一个经纬度路径是否为顺时针
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **boolean**
### typePolygon
判断一个经纬度路径面类型
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **boolean**
### typePolygon
判断一个经纬度路径面类型
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **boolean**
### makesureClockwise
将一个路径变为顺时针
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **Array<\[number, number]>**
### makesureClockwise
将一个路径变为顺时针
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **Array<\[number, number]>**
### makesureAntiClockwise
将一个路径变为逆时针
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **Array<\[number, number]>**
### makesureAntiClockwise
将一个路径变为逆时针
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **Array<\[number, number]>**
### distanceOfLine
计算一个经纬度路径的实际长度。单位:米
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **number**
### distanceOfLine
计算一个经纬度路径的实际长度。单位:米
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **number**
### ringRingClip
计算两个经纬度面的交叉区域。只适用于凸多边形
#### Parameters
- `ring1` **Array<LngLatLike>**
- `ring2` **Array<LngLatLike>**
### ringRingClip
计算两个经纬度面的交叉区域。只适用于凸多边形
#### Parameters
- `ring1` **Array<LngLatLike>**
- `ring2` **Array<LngLatLike>**
### doesSegmentsIntersect
判断两个线段是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
- `p4` **LngLatLike**
Returns **boolean**
### doesSegmentsIntersect
判断两个线段是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
- `p4` **LngLatLike**
Returns **boolean**
### doesSegmentLineIntersect
判断线段和一个路径是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `line` **Array<LngLatLike>**
Returns **boolean**
### doesSegmentLineIntersect
判断线段和一个路径是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `line` **Array<LngLatLike>**
Returns **boolean**
### doesSegmentRingIntersect
判断线段和一个环是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### doesSegmentRingIntersect
判断线段和一个环是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### doesSegmentPolygonIntersect
判断线段和多个环是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
Returns **boolean**
### doesSegmentPolygonIntersect
判断线段和多个环是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
Returns **boolean**
### doesLineLineIntersect
判断两个经纬度路径是否相交
#### Parameters
- `line` **Array<LngLatLike>**
- `line` **Array<LngLatLike>**
Returns **boolean**
### doesLineLineIntersect
判断两个经纬度路径是否相交
#### Parameters
- `line` **Array<LngLatLike>**
- `line` **Array<LngLatLike>**
Returns **boolean**
### doesLineRingIntersect
判断经纬度路径和经纬度面是否交叉
#### Parameters
- `line` **Array<LngLatLike>**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### doesLineRingIntersect
判断经纬度路径和经纬度面是否交叉
#### Parameters
- `line` **Array<LngLatLike>**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### doesRingRingIntersect
判断两个经纬度面是否交叉
#### Parameters
- `ring1` **Array<LngLatLike>**
- `ring2` **Array<LngLatLike>**
Returns **boolean**
### doesRingRingIntersect
判断两个经纬度面是否交叉
#### Parameters
- `ring1` **Array<LngLatLike>**
- `ring2` **Array<LngLatLike>**
Returns **boolean**
### pointInRing
判断点是否在环内,支持任意坐标系
#### Parameters
- `p` **LngLatLike**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### pointInRing
判断点是否在环内,支持任意坐标系
#### Parameters
- `p` **LngLatLike**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### isPointInRing
判断点是否在环内
#### Parameters
- `p` **LngLatLike**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### isPointInRing
判断点是否在环内
#### Parameters
- `p` **LngLatLike**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### isPointInBbox
判断点是否在环内
#### Parameters
- `p` **LngLatLike**
- `bbox` **Array<LngLatLike>**
Returns **boolean**
### isPointInBbox
判断点是否在 bbox内
#### Parameters
- `p` **LngLatLike**
- `rect` **Array<LngLatLike>**
Returns **boolean**
### isRingInRing
判断环是否在另一个环内
#### Parameters
- `ring1` **Array<LngLatLike>**
- `ring2` **Array<LngLatLike>**
Returns **boolean**
### isRingInRing
判断环是否在另一个环内
#### Parameters
- `ring1` **Array<LngLatLike>**
- `ring2` **Array<LngLatLike>**
Returns **boolean**
### isPointInPolygon
判断点是否在多个环组成区域内
#### Parameters
- `p` **LngLatLike**
- `rings` **\[Array<ringLngLatLike>]**
Returns **boolean**
### isPointInPolygon
判断点是否在多个环组成区域内
#### Parameters
- `p` **LngLatLike**
- `rings` **\[Array<ringLngLatLike>]**
Returns **boolean**
### isPointInPolygons
判断点是否在带洞多多边型内
#### Parameters
- `p` **LngLatLike**
- `polygons` **\[\[Array<ringLngLatLike>]]**
Returns **boolean**
### isPointOnSegment
判断P1是否在P2P3上,tolerance为误差范围
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
- `tolerance` **Number**
Returns **boolean**
### isPointOnSegment
判断P1是否在P2P3上,tolerance为误差范围
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
- `tolerance` **Number**
Returns **boolean**
### isPointOnLine
判断P是否在line上,tolerance为误差范围
#### Parameters
- `p` **LngLatLike**
- `line` **Array<LngLatLike>**
- `tolerance` **number**
Returns **boolean**
### isPointOnLine
判断P是否在line上,tolerance为误差范围
#### Parameters
- `p` **LngLatLike**
- `line` **Array<LngLatLike>**
- `tolerance` **number**
Returns **boolean**
### isPointOnRing
判断P是否在ring的边上,tolerance为误差范围
#### Parameters
- `p` **LngLatLike**
- `ring` **Array<LngLatLike>**
- `tolerance` **number**
Returns **boolean**
### isPointOnRing
判断P是否在ring的边上,tolerance为误差范围
#### Parameters
- `p` **LngLatLike**
- `ring` **Array<LngLatLike>**
- `tolerance` **number**
Returns **boolean**
### isPointOnPolygon
判断P是否在多个ring的边上,tolerance为误差范围
#### Parameters
- `p` **LngLatLike**
- `tolerance` **number**
Returns **boolean**
### isPointOnPolygon
判断P是否在多个ring的边上,tolerance为误差范围
#### Parameters
- `p` **LngLatLike**
- `tolerance` **number**
Returns **boolean**
### closestOnSegment
计算P2P3上距离P1最近的点
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
Returns **boolean**
### closestOnSegment
计算P2P3上距离P1最近的点
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
Returns **boolean**
### closestOnLine
计算line上距离P最近的点
#### Parameters
- `p` **LngLatLike**
- `line` **Array<LngLatLike>**
Returns **boolean**
### closestOnLine
计算line上距离P最近的点
#### Parameters
- `p` **LngLatLike**
- `line` **Array<LngLatLike>**
Returns **boolean**
### distanceToSegment
计算P2P3到P1的距离。单位:米
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
Returns **LngLat**
### distanceToSegment
计算P2P3到P1的距离。单位:米
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
Returns **LngLat**
### distanceToLine
计算P到line的距离。单位:米
#### Parameters
- `p` **LngLatLike**
- `line` **Array<LngLatLike>**
Returns **number**
### distanceToLine
计算P到line的距离。单位:米
#### Parameters
- `p` **LngLatLike**
- `line` **Array<LngLatLike>**
Returns **number**
## GeometryUtil
平面的计算库
### distance
计算两个经纬度点之间的实际距离。单位:米
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
Returns **number**
### distance
计算两个经纬度点之间的实际距离。单位:米
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
Returns **number**
### ringArea
计算一个经纬度路径围成区域的实际面积。单位:平米
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **number**
### ringArea
计算一个经纬度路径围成区域的实际面积。单位:平米
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **number**
### isClockwise
判断一个经纬度路径是否为顺时针
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **boolean**
### isClockwise
判断一个经纬度路径是否为顺时针
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **boolean**
### typePolygon
判断一个经纬度路径面类型
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **boolean**
### typePolygon
判断一个经纬度路径面类型
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **boolean**
### makesureClockwise
将一个路径变为顺时针
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **Array<\[number, number]>**
### makesureClockwise
将一个路径变为顺时针
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **Array<\[number, number]>**
### makesureAntiClockwise
将一个路径变为逆时针
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **Array<\[number, number]>**
### makesureAntiClockwise
将一个路径变为逆时针
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **Array<\[number, number]>**
### distanceOfLine
计算一个经纬度路径的实际长度。单位:米
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **number**
### distanceOfLine
计算一个经纬度路径的实际长度。单位:米
#### Parameters
- `ring` **Array<LngLatLike>**
Returns **number**
### ringRingClip
计算两个经纬度面的交叉区域。只适用于凸多边形
#### Parameters
- `ring1` **Array<LngLatLike>**
- `ring2` **Array<LngLatLike>**
### ringRingClip
计算两个经纬度面的交叉区域。只适用于凸多边形
#### Parameters
- `ring1` **Array<LngLatLike>**
- `ring2` **Array<LngLatLike>**
### doesSegmentsIntersect
判断两个线段是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
- `p4` **LngLatLike**
Returns **boolean**
### doesSegmentsIntersect
判断两个线段是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
- `p4` **LngLatLike**
Returns **boolean**
### doesSegmentLineIntersect
判断线段和一个路径是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `line` **Array<LngLatLike>**
Returns **boolean**
### doesSegmentLineIntersect
判断线段和一个路径是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `line` **Array<LngLatLike>**
Returns **boolean**
### doesSegmentRingIntersect
判断线段和一个环是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### doesSegmentRingIntersect
判断线段和一个环是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### doesSegmentPolygonIntersect
判断线段和多个环是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
Returns **boolean**
### doesSegmentPolygonIntersect
判断线段和多个环是否相交
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
Returns **boolean**
### doesLineLineIntersect
判断两个经纬度路径是否相交
#### Parameters
- `line` **Array<LngLatLike>**
- `line` **Array<LngLatLike>**
Returns **boolean**
### doesLineLineIntersect
判断两个经纬度路径是否相交
#### Parameters
- `line` **Array<LngLatLike>**
- `line` **Array<LngLatLike>**
Returns **boolean**
### doesLineRingIntersect
判断经纬度路径和经纬度面是否交叉
#### Parameters
- `line` **Array<LngLatLike>**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### doesLineRingIntersect
判断经纬度路径和经纬度面是否交叉
#### Parameters
- `line` **Array<LngLatLike>**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### doesRingRingIntersect
判断两个经纬度面是否交叉
#### Parameters
- `ring1` **Array<LngLatLike>**
- `ring2` **Array<LngLatLike>**
Returns **boolean**
### doesRingRingIntersect
判断两个经纬度面是否交叉
#### Parameters
- `ring1` **Array<LngLatLike>**
- `ring2` **Array<LngLatLike>**
Returns **boolean**
### pointInRing
判断点是否在环内,支持任意坐标系
#### Parameters
- `p` **LngLatLike**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### pointInRing
判断点是否在环内,支持任意坐标系
#### Parameters
- `p` **LngLatLike**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### isPointInRing
判断点是否在环内
#### Parameters
- `p` **LngLatLike**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### isPointInRing
判断点是否在环内
#### Parameters
- `p` **LngLatLike**
- `ring` **Array<LngLatLike>**
Returns **boolean**
### isPointInBbox
判断点是否在环内
#### Parameters
- `p` **LngLatLike**
- `bbox` **Array<LngLatLike>**
Returns **boolean**
### isPointInBbox
判断点是否在 bbox内
#### Parameters
- `p` **LngLatLike**
- `rect` **Array<LngLatLike>**
Returns **boolean**
### isRingInRing
判断环是否在另一个环内
#### Parameters
- `ring1` **Array<LngLatLike>**
- `ring2` **Array<LngLatLike>**
Returns **boolean**
### isRingInRing
判断环是否在另一个环内
#### Parameters
- `ring1` **Array<LngLatLike>**
- `ring2` **Array<LngLatLike>**
Returns **boolean**
### isPointInPolygon
判断点是否在多个环组成区域内
#### Parameters
- `p` **LngLatLike**
- `rings` **\[Array<ringLngLatLike>]**
Returns **boolean**
### isPointInPolygon
判断点是否在多个环组成区域内
#### Parameters
- `p` **LngLatLike**
- `rings` **\[Array<ringLngLatLike>]**
Returns **boolean**
### isPointInPolygons
判断点是否在带洞多多边型内
#### Parameters
- `p` **LngLatLike**
- `polygons` **\[\[Array<ringLngLatLike>]]**
Returns **boolean**
### isPointOnSegment
判断P1是否在P2P3上,tolerance为误差范围
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
- `tolerance` **Number**
Returns **boolean**
### isPointOnSegment
判断P1是否在P2P3上,tolerance为误差范围
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
- `tolerance` **Number**
Returns **boolean**
### isPointOnLine
判断P是否在line上,tolerance为误差范围
#### Parameters
- `p` **LngLatLike**
- `line` **Array<LngLatLike>**
- `tolerance` **number**
Returns **boolean**
### isPointOnLine
判断P是否在line上,tolerance为误差范围
#### Parameters
- `p` **LngLatLike**
- `line` **Array<LngLatLike>**
- `tolerance` **number**
Returns **boolean**
### isPointOnRing
判断P是否在ring的边上,tolerance为误差范围
#### Parameters
- `p` **LngLatLike**
- `ring` **Array<LngLatLike>**
- `tolerance` **number**
Returns **boolean**
### isPointOnRing
判断P是否在ring的边上,tolerance为误差范围
#### Parameters
- `p` **LngLatLike**
- `ring` **Array<LngLatLike>**
- `tolerance` **number**
Returns **boolean**
### isPointOnPolygon
判断P是否在多个ring的边上,tolerance为误差范围
#### Parameters
- `p` **LngLatLike**
- `tolerance` **number**
Returns **boolean**
### isPointOnPolygon
判断P是否在多个ring的边上,tolerance为误差范围
#### Parameters
- `p` **LngLatLike**
- `tolerance` **number**
Returns **boolean**
### closestOnSegment
计算P2P3上距离P1最近的点
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
Returns **boolean**
### closestOnSegment
计算P2P3上距离P1最近的点
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
Returns **boolean**
### closestOnLine
计算line上距离P最近的点
#### Parameters
- `p` **LngLatLike**
- `line` **Array<LngLatLike>**
Returns **boolean**
### closestOnLine
计算line上距离P最近的点
#### Parameters
- `p` **LngLatLike**
- `line` **Array<LngLatLike>**
Returns **boolean**
### distanceToSegment
计算P2P3到P1的距离。单位:米
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
Returns **LngLat**
### distanceToSegment
计算P2P3到P1的距离。单位:米
#### Parameters
- `p1` **LngLatLike**
- `p2` **LngLatLike**
- `p3` **LngLatLike**
Returns **LngLat**
### distanceToLine
计算P到line的距离。单位:米
#### Parameters
- `p` **LngLatLike**
- `line` **Array<LngLatLike>**
Returns **number**
### distanceToLine
计算P到line的距离。单位:米
#### Parameters
- `p` **LngLatLike**
- `line` **Array<LngLatLike>**
Returns **number**
## DomUtil
### getViewport
获取DOM元素的大小
#### Parameters
- `obj` **HTMLElement**
Returns **\[number, number]**
### getViewportOffset
获取DOM元素距离窗口左上角的距离
#### Parameters
- `element` **HTMLElement**
Returns **\[number, number]**
### create
在parentNode内部创建一个className类名的tagName元素
#### Parameters
- `tagName` **string** 节点类型
- `container` **HTMLElement** 上级节点对象
- `className` **string**
- `position` **string** 插入位置
Returns **HTMLElement**
### hasClass
DOM元素是否包含className
#### Parameters
- `el` **HTMLElement**
- `name` **string**
Returns **boolean**
### addClass
给DOM元素添加一个className
#### Parameters
- `el` **HTMLElement**
- `name` **string**
### setClass
给DOM元素设置为className样式
#### Parameters
- `el` **HTMLElement**
- `name` **string**
### removeClass
给DOM元素删除一个className
#### Parameters
- `el` **HTMLElement**
- `name` **string**
### remove
将DOM元素从父节点删除
#### Parameters
- `el` **HTMLElement**
### empty
清空DOM元素
#### Parameters
- `el` **HTMLElement**
### rotate
给DOM元素旋转一个角度,以center为中心,center以元素左上角为坐标原点
#### Parameters
- `target` **HTMLElement**
- `angle` **number**
- `center` **Pixel**
### setCss
给DOM元素删除一组样式,Object同样式表
#### Parameters
- `obj` **(HTMLElement \| Array<HTMLElement>)**
- `css` **Object**
### setOpacity
给DOM元素设定一个透明度
#### Parameters
- `el` **HTMLElement**
- `value` **number**
## Browser
### Properties
- `us` **string** 当前浏览器userAgent
- `mobile` **boolean** 是否移动设备
- `plat` **string** 平台类型,如:'windows'、'mac'、'ios'、'android'、'other'
- `windows` **boolean** 是否windows设备
- `ios` **boolean** 是否iOS设备
- `iPad` **boolean** 是否iPad
- `Phone` **boolean** 是否iPhone
- `android` **boolean** 是否安卓设备
- `android23` **boolean** 是否安卓4以下系统
- `chrome` **boolean** 是否Chrome浏览器
- `firefox` **boolean** 是否火狐浏览器
- `safari` **boolean** 是否Safari浏览器
- `wechat` **boolean** 是否微信
- `uc` **boolean** 是否UC浏览器
- `qq` **boolean** 是否QQ或者QQ浏览器
- `ie` **boolean** 是否IE
- `ie6` **boolean** 是否IE6
- `ie7` **boolean** 是否IE7
- `ie8` **boolean** 是否IE8
- `ie9` **boolean** 是否IE9
- `ie10` **boolean** 是否IE10
- `ie11` **boolean** 是否IE11
- `ielt9` **boolean** 是否IE9以下
- `edge` **boolean** 是否Edge浏览器
- `isLocalStorage` **boolean** 是否支持LocaStorage
- `isGeolocation` **boolean** 是否支持Geolocation
- `mobileWebkit` **boolean** 是否Webkit移动浏览器
- `mobileWebkit3d` **boolean** 是否支持Css3D的Webkit移动端浏览器
- `retina` **boolean** 是否高清屏幕,devicePixelRatio>1
- `touch` **boolean** 是否触屏
- `msPointer` **boolean** 是否msPointer设备
- `pointer` **boolean** 是否pointer设备
- `webkit` **boolean** 是否webkit浏览器
- `webkit3d` **boolean** 是否支持Css3D的Webkit浏览器
- `gecko3d` **boolean** 是否支持Css3D的gecko浏览器
- `ie3d` **boolean** 是否支持Css3D的ie浏览器
- `any3d` **boolean** 是否支持Css3D的浏览器
- `opera3d` **boolean** 是否支持Css3D的opera浏览器
- `isCanvas` **boolean** 是否支持canvas
- `isSvg` **boolean** 是否支持svg
- `isVML` **boolean** 是否支持vml
- `isWorker` **boolean** 是否支持WebWorker
- `isWebsocket` **boolean** 是否支持WebSocket
- `isWebGL` **boolean** 是否支持webgl
## Util
### isDOM
判断参数是否为DOM元素
#### Parameters
- `obj` **any**
Returns **boolean**
### colorNameToHex
#### Parameters
- `colorName` **string**
Returns **string** 如#FFFFFF的颜色值
### rgbHex2Rgba
将16进制RGB转为rgba(R,G,B,A)
#### Parameters
- `hex` **string**
Returns **string**
### argbHex2Rgba
将16进制RGBA转为rgba(R,G,B,A)
#### Parameters
- `hex` **string**
Returns **string**
### isEmpty
判断一个对象是否为空
#### Parameters
- `obj` **any**
Returns **boolean**
### deleteItemFromArray
从数组删除元素
#### Parameters
- `array` **any**
- `item` **any**
### deleteItemFromArrayByIndex
按索引删除数组元素
#### Parameters
- `array` **any**
- `index` **number**
### indexOf
返回元素索引
#### Parameters
- `array` **any**
- `item` **any**
Returns **number**
### format
保留小数点后digits位
#### Parameters
- `num` **number**
- `digits` **number**
Returns **number**
### isArray
判断是否数组
#### Parameters
- `obj` **any**
Returns **boolean**
### includes
判断数组是否包含某个元素
#### Parameters
- `array` **Array<any>**
- `item` **any**
Returns **boolean**
### requestIdleCallback
同原生requestIdleCallback
#### Parameters
- `func` **Function**
Returns **number**
### cancelIdleCallback
同原生 cancelIdleCallback
#### Parameters
- `id` **number**
### requestAnimFrame
同原生 Util.requestAnimFrame
#### Parameters
- `func` **Function**
Returns **number**
### cancelAnimFrame
同原生 Util.cancelAnimFrame
#### Parameters
- `id` **number**
FILE:references/api/context-menu.md
## 右键菜单
## ContextMenu
**Extends OverlayDOM**
右键菜单 [亲手试一试][82]
### Parameters
- `opts` **OverlayOptions** 右键菜单参数
- `opts.position` **(Vector2 | LngLat)** 右键菜单显示的位置
- `opts.content` **(string \| HTMLElement)** 右键菜单内容(针对自定义菜单时,添加菜单内容及功能。可以是HTML要素字符串或者HTML DOM对象。)
### Examples
```javascript
// 创建一个右键菜单实例
var contextMenu = new AMap.ContextMenu();
//右键放大
contextMenu.addItem("放大一级", function () {
var zoom = map.getZoom();
map.setZoom(zoom++);
}, 0);
// 在地图上指定位置打开右键菜单
contextMenu.open(map, [116.397389,39.909466]);
```
### open
打开右键菜单
#### Parameters
- `map` **Map**
- `position` **Vector2**
### close
关闭右键菜单
### addItem
菜单添加一条内容
#### Parameters
- `text` **string**
- `fn` **EventListener**
- `num` **number**
### removeItem
菜单移除一条内容
#### Parameters
- `text` **string**
- `fn` **EventListener**
FILE:references/api/controls.md
## 地图控件
固定于地图最上层的用于控制地图某些状态的 DOM 组件类型
## Control
**Extends \_Event.Event**
### Parameters
- `opts`
### addTo
添加控件到地图上
#### Parameters
- `map` **Map** 地图实例
### remove
从地图上移除控件
### show
设置控件可见
### hide
设置控件隐藏
## Control
**Extends Event**
地图控件基类,可扩展做自定义地图控件。
### Parameters
- `opts` **ControlConfig** 默认参数
- `opts.position` **(string \| object)** 控件停靠位置
{ top: 5; left: 5; right: 5; bottom: 5 } 或者
'LT': 左上角, 'RT': 右上角, 'LB': 左下角, 'RB': 右下角
- `opts.offset` **\[number, number]** 相对于地图容器左上角的偏移量,正数代表向右下偏移。默认为AMap.Pixel(10,10)
### addTo
添加控件到地图上
#### Parameters
- `map` **Map** 地图实例
### remove
从地图上移除控件
### show
设置控件可见
### hide
设置控件隐藏
## Scale
**Extends AMap.Control**
比例尺插件。位于地图右下角,用户可控制其显示与隐藏。继承自 AMap.Control </br>
[相关示例][87]
### Parameters
- `opts` **ControlConfig** 默认参数
- `opts.position` **(string \| object)** 控件停靠位置
{ top: 5; left: 5; right: 5; bottom: 5 } 或者
'LT': 左上角, 'RT': 右上角, 'LB': 左下角, 'RB': 右下角
- `opts.offset` **\[number, number]** 相对于地图容器左上角的偏移量,正数代表向右下偏移。默认为AMap.Pixel(10,10)
### Examples
```javascript
mapObj.plugin(["AMap.Scale"],function(){
var scale = new AMap.Scale();
mapObj.addControl(scale);
});
```
### addTo
添加控件到地图上
#### Parameters
- `map` **Map** 地图实例
### removeFrom
从地图上移除控件
### show
设置控件可见
### hide
设置控件隐藏
## ToolBar
**Extends AMap.Control**
地图操作工具条插件。可支持方向导航、位置定位、视野级别缩放、视野级别选择等操作。继承自 AMap.Control </br>
[相关示例][87]
### Parameters
- `opts` **ControlConfig** 默认参数
- `opts.position` **(String \| Object)** 控件停靠位置
{ top: 5; left: 5; right: 5; bottom: 5 } 或者
'LT': 左上角, 'RT': 右上角, 'LB': 左下角, 'RB': 右下角
- `opts.offset` **\[Number, Number]** 相对于地图容器左上角的偏移量,正数代表向右下偏移。默认为AMap.Pixel(10,10)
### Examples
```javascript
mapObj.plugin(["AMap.ToolBar"],function(){
//加载工具条
var tool = new AMap.ToolBar();
mapObj.addControl(tool);
});
```
### addTo
添加控件到地图上
#### Parameters
- `map` **Map** 地图实例
### remove
从地图上移除控件
### show
设置控件可见
### hide
设置控件隐藏
## ControlBar
**Extends AMap.Control**
组合了旋转、倾斜、复位在内的地图控件。 </br>
[相关示例][87]
### Parameters
- `opts` **ControlConfig** 默认参数
- `opts.position` **(string \| object)** 控件停靠位置
{ top: 5; left: 5; right: 5; bottom: 5 } 或者
'LT': 左上角, 'RT': 右上角, 'LB': 左下角, 'RB': 右下角
- `opts.offset` **\[number, number]** 相对于地图容器左上角的偏移量,正数代表向右下偏移。默认为AMap.Pixel(10,10)
- `opts.showControlButton` **boolean** 是否显示倾斜、旋转按钮。默认为 true
### Examples
```javascript
var mapObj = new AMap.Map("container",{
center: new AMap.LngLat(116.368904,39.913423),
zoom:16
});
mapObj.plugin(["AMap.ControlBar"],function() {
var controlBar = new AMap.ControlBar(Options)
map.addControl(controlBar)
});
//map.reoveControl(controlBar)
```
### addTo
添加控件到地图上
#### Parameters
- `map` **Map** 地图实例
### remove
从地图上移除控件
### show
设置控件可见
### hide
设置控件隐藏
## MapType
**Extends AMap.Control**
### Parameters
- `opts`
### addLayer
添加一个图层
#### Parameters
- `layerInfo` **LayerInfo** 图层信息,需要包含图层对象
- `layerInfo.id` **String** 图层 id
- `layerInfo.enable` **String** 图层是否可用
- `layerInfo.name` **String** 图层暂时名称
- `layerInfo.type` **(`"base"` \| `"overlay"`)** 图层类型,base 是属于底图图层,overlay 属于叠加图层。
- `layerInfo.layer` **Layer** 图层对象
- `layerInfo.show` **Boolean** 图层是否显示
### removeLayer
移除一个图层
#### Parameters
- `id` **String** 图层 id
### addTo
添加控件到地图上
#### Parameters
- `map` **Map** 地图实例
### remove
从地图上移除控件
### show
设置控件可见
### hide
设置控件隐藏
## MapType
**Extends AMap.Control**
### Parameters
- `opts`
### addLayer
添加一个图层
#### Parameters
- `layerInfo` **LayerInfo** 图层信息,需要包含图层对象
- `layerInfo.id` **String** 图层 id
- `layerInfo.enable` **String** 图层是否可用
- `layerInfo.name` **String** 图层暂时名称
- `layerInfo.type` **(`"base"` \| `"overlay"`)** 图层类型,base 是属于底图图层,overlay 属于叠加图层。
- `layerInfo.layer` **Layer** 图层对象
- `layerInfo.show` **Boolean** 图层是否显示
### removeLayer
移除一个图层
#### Parameters
- `id` **String** 图层 id
### addTo
添加控件到地图上
#### Parameters
- `map` **Map** 地图实例
### remove
从地图上移除控件
### show
设置控件可见
### hide
设置控件隐藏
## MapType
**Extends AMap.Control**
地图类型切换插件。用户通过该插件进行地图切换。
### Parameters
- `opts` **MaptypeOptions** 控件默认参数
- `opts.defaultType` **number** 初始化默认图层类型。 取值为0:默认底图 取值为1:卫星图 默认值:0 (optional, default `0`)
- `opts.showTraffic` **boolean** 叠加实时交通图层 默认值:false (optional, default `false`)
- `opts.showRoad` **boolean** 叠加路网图层 默认值:false (optional, default `false`)
### Examples
```javascript
mapObj = new AMap.Map("container",{
center:new AMap.LngLat(116.368904,39.913423),
zoom: 16
});
mapObj.plugin(["AMap.MapType"],function(){
//地图类型切换
var type= new AMap.MapType({
defaultType: 0,
});
mapObj.addControl(type);
});
```
### addLayer
添加一个图层
#### Parameters
- `layerInfo` **LayerInfo** 图层信息,需要包含图层对象
- `layerInfo.id` **String** 图层 id
- `layerInfo.enable` **String** 图层是否可用
- `layerInfo.name` **String** 图层暂时名称
- `layerInfo.type` **(`"base"` \| `"overlay"`)** 图层类型,base 是属于底图图层,overlay 属于叠加图层。
- `layerInfo.layer` **Layer** 图层对象
- `layerInfo.show` **Boolean** 图层是否显示
### removeLayer
移除一个图层
#### Parameters
- `id` **String** 图层 id
### addTo
添加控件到地图上
#### Parameters
- `map` **Map** 地图实例
### remove
从地图上移除控件
### show
设置控件可见
### hide
设置控件隐藏
## HawkEye
**Extends AMap.Control**
鹰眼控件,用于显示缩略地图,显示于地图右下角,可以随主图的视口变化而变化,也可以配置成固定位置实现类似于南海附图的效果。
### Parameters
- `options` **HawkEyeOptions** 初始化参数
- `options.autoMove` **boolean** 是否随主图视口变化移动
- `options.showRectangle` **boolean** 是否显示视口矩形
- `options.showButton` **boolean** 是否显示打开关闭的按钮
- `options.opened` **boolean** 默认是否展开
- `options.mapStyle` **string** 缩略图要显示的地图自定义样式,如'amap://styles/dark'
- `options.layers` **array** 缩略图要显示的图层类型,默认为普通矢量地图
- `options.width` **string** 缩略图的宽度,同CSS,如'200px'
- `options.height` **string** 缩略图的高度,同CSS,如'200px'
- `options.offset` **\[number, number]** 缩略图距离地图右下角的像素距离,如[2,2]
- `options.borderStyle` **string** 缩略图的边框样式,同CSS,如"double solid solid double"
- `options.borderColor` **string** 缩略图的边框颜色,同CSS,如'silver'
- `options.borderRadius` **string** 缩略图的圆角半径,同CSS,如'5px'
- `options.borderWidth` **string** 缩略图的边框宽度,同CSS,如'2px'
- `options.buttonSize` **string** 缩略图的像素尺寸,同CSS,如'12px'
### show
恢复鹰眼控件的正常大小
### hide
最小化鹰眼控件
FILE:references/api/events.md
## 事件
地图 JSAPI 具有完备的事件体系,在 2.0 版本中所有类型的实例均使用 on/off 方法进行时间的绑定和移除
## Event
JSAPI 的所有类型(地图、图层、覆盖物等)都实现了事件接口,用于给当前实例对象绑定、移除、清理事件回调
### Examples
```javascript
// 声明点击事件的回调函数
function onClick(e){
console.log(e);
}
// 给地图实例绑定点击事件 onClick
map.on('click', onClick);
// 移除地图实例的 onClick 事件绑定
map.off('click', onClick);
// 清除地图实例上的所有 click 事件绑定
map.clearEvents('click');
// 覆盖物绑定鼠标移动事件
polygon.on('mousemove',console.log);
// 覆盖物绑定事件判断
polygon.hasEvents('mousemove',console.log);
```
### on
给实例绑定事件回调函数,同一个类型、同一个回调函数、同一个上下文只会绑定一次
#### Parameters
- `type` **String** 事件类型
- `function` **Function** 回调函数
- `context` **Object** 事件上下文,缺省为实例本身
- `once` **Boolean** 是否只执行一次
Returns **Object** 当前实例
### once
给实例绑定只执行一次的事件回调
#### Parameters
- `type` **String** 事件类型
- `fn` **Function** 回调函数
- `context` **Object** 事件上下文,缺省为实例本身
Returns **Object** 当前实例
### off
移除当前实例的某一个事件回调
#### Parameters
- `type` **String** 事件类型
- `function` **Function** 事件回调函数
- `context` **Object** 事件上下文,缺省为当前实例
Returns **Object** 当前实例
### hasEvents
判断当前实例是否已经绑定了某个事件回调
#### Parameters
- `type` **String** 事件类型
- `function` **Function** 事件回调
- `context` **Object** 事件上下文
Returns **Boolean**
### clearEvents
清除当前实例某一类型的全部事件回调
#### Parameters
- `type` **String** 事件类型,如果此参数为空,清除实例上的所有绑定的事件回调
Returns **Object** 当前实例
### emit
模拟触发当前实例的某个事件
#### Parameters
- `type` **String** 事件类型
- `data` **Object** 事件回调时返回的数据,模拟的事件体应该完整,否则可能导致报错
Returns **Object** 当前实例
FILE:references/api/foundation.md
## 基础类
经纬度、像素、边界、大小、这些是地图 JSAPI 开发必须了解的基本类型
## LngLat
### Parameters
- `lng`
- `lat`
- `noWrap` (optional, default `false`)
### lat
纬度
Type: number
### lng
经度
Type: number
### setLng
设置经度值
#### Parameters
- `lng` **number** 经度
### setLat
设置纬度值
#### Parameters
- `lat` **number**
### getLng
获取经度值
Returns **number**
### getLat
获取纬度值
Returns **number**
### equals
判断经纬度坐标和另外一个经纬度坐标是否相等
#### Parameters
- `another` **LngLat** 另外一个经纬度坐标
Returns **Boolean** 是否相等
### add
与另外一个经纬度相加
#### Parameters
- `another` **LngLat** 另外一个经纬度坐标
- `noWrap` **boolean** 是否将相加的结果经度值修正到 [-180,180] 区间内
Returns **LngLat** 两个经纬度相加的结果
### subtract
与另外一个经纬度相减
#### Parameters
- `another` **LngLat** 另外一个经纬度坐标
- `noWrap` **boolean** 是否将相减的结果经度值修正到 [-180,180] 区间内
Returns **LngLat** 两个经纬度相减的结果
### offset
获取从当前经纬度位置向东移动 E 米,向北移动 N 米的坐标位置
#### Parameters
- `E` **Number** 经度方向移动,向东为正
- `N` **Number** 维度方向移动,向北为正
Returns **LngLat** 移动后的新经纬度
### toString
LngLat对象以字符串的形式返回
Returns **string** 格式如'lng值,lat值'的字符串
### toArray
LngLat对象以字符串的形式返回
Returns **string** 格式如'lng值,lat值'的字符串
### distance
计算当前经纬度距离另一个经纬度或者经纬度数组组成的路径的距离
[相关示例][5]
Returns **number** 距离值,单位为米
## LngLat
经纬度坐标,用来描述地图上的一个点位置,
目前高德地图使用的是 GCJ-02 坐标,如果你采集的是 WGS84 坐标,请先进行坐标转换
### Parameters
- `lng` **number** 经度值
- `lat` **number** 纬度值
- `noWrap` **boolean** 是否自动将经度值修正到 [-180,180] 区间内,缺省为false;
noWrap 为false时传入[190,30],会被自动修正为[-170,30],
noWrap 为true时不会自动修正,可以用来进行跨日期限的覆盖物绘制
### Examples
```javascript
var lnglat = new AMap.LngLat(116, 39);
```
### lat
纬度
Type: number
### lng
经度
Type: number
### setLng
设置经度值
#### Parameters
- `lng` **number** 经度
### setLat
设置纬度值
#### Parameters
- `lat` **number**
### getLng
获取经度值
Returns **number**
### getLat
获取纬度值
Returns **number**
### equals
判断经纬度坐标和另外一个经纬度坐标是否相等
#### Parameters
- `another` **LngLat** 另外一个经纬度坐标
Returns **Boolean** 是否相等
### add
与另外一个经纬度相加
#### Parameters
- `another` **LngLat** 另外一个经纬度坐标
- `noWrap` **boolean** 是否将相加的结果经度值修正到 [-180,180] 区间内
Returns **LngLat** 两个经纬度相加的结果
### subtract
与另外一个经纬度相减
#### Parameters
- `another` **LngLat** 另外一个经纬度坐标
- `noWrap` **boolean** 是否将相减的结果经度值修正到 [-180,180] 区间内
Returns **LngLat** 两个经纬度相减的结果
### offset
获取从当前经纬度位置向东移动 E 米,向北移动 N 米的坐标位置
#### Parameters
- `E` **Number** 经度方向移动,向东为正
- `N` **Number** 维度方向移动,向北为正
Returns **LngLat** 移动后的新经纬度
### toString
LngLat对象以字符串的形式返回
Returns **string** 格式如'lng值,lat值'的字符串
### toArray
LngLat对象以字符串的形式返回
Returns **string** 格式如'lng值,lat值'的字符串
### distance
计算当前经纬度距离另一个经纬度或者经纬度数组组成的路径的距离
[相关示例][5]
Returns **number** 距离值,单位为米
## Bounds
地物对象的经纬度矩形范围。
### Parameters
- `southWest` **LngLat** 西南角经纬度
- `northEast` **LngLat** 东北角经纬度值
### getSouthWest
获取西南角坐标。
Returns **LngLat**
### getNorthEast
获取东北角坐标
Returns **LngLat**
### getNorthEast
获取西北角坐标
Returns **LngLat**
### getNorthEast
获取东南角坐标
Returns **LngLat**
### contains
指定点坐标是否在矩形范围内
[相关示例][6]
#### Parameters
- `obj` **LngLat**
#### Examples
```javascript
bounds.contains(new AMap.LngLat(116,39));
```
Returns **Boolean**
### getCenter
获取当前Bounds的中心点经纬度坐标。
Returns **LngLat**
### toString
以字符串形式返回地图对象的矩形范围
Returns **String**
## Pixel
像素坐标,确定地图上的一个像素点。
### Parameters
- `x` **number**
- `y` **number**
### getX
获取像素横坐标
Returns **Number**
### getY
获取像素纵坐标
Returns **Number**
### toString
以字符串形式返回像素坐标对象
Returns **string**
### equals
当前像素坐标与传入像素坐标是否相等
#### Parameters
- `point` **Pixel**
Returns **boolean**
## Size
地物对象的像素尺寸
### Parameters
- `width` **number** 宽度
- `height` **number** 高度
### getWidth
获取像素横坐标
Returns **Number**
### getHeight
获取像素纵坐标
Returns **Number**
### toString
以字符串形式返回尺寸大小对象
Returns **string**
FILE:references/api/geocoder.md
## 地理编码
用于经纬度与地址之间的相互查询
## Geocoder
**Extends AMap.Event**
AMap.Geocoder 地理编码与逆地理编码类,用于地址描述与经纬度坐标之间的转换。用户可以通过回调函数获取查询结果。
[相关示例][103]
### Parameters
- `opts` **GeocoderOptions**
- `opts.city` **string** <div>
<div>城市,地理编码时,设置地址描述所在城市</div>
<div>可选值:城市名(中文或中文全拼)、citycode、adcode</div>
<div>默认值:“全国”</div>
</div>
- `opts.radius` **number** <div>
<div>逆地理编码时,以给定坐标为中心点,单位:米</div>
<div>取值范围:0 - 3000</div>
<div>默认值:1000</div>
</div>
- `opts.lang` **string** <div>设置语言类型</div>
<div>可选值:zh_cn(中文)、en(英文)</div>
<div>默认值:zh_cn(中文</div>
- `opts.batch` **boolean** 是否批量查询<div>batch 设置为 false 时,只返回第一条记录</div>
- `opts.extensions` **string** 逆地理编码时,返回信息的详略<div>默认值:base,返回基本地址信息 </div>
<div>取值为:all,返回地址信息及附近poi、道路、道路交叉口等信息 </div>
### Examples
```javascript
var geocoder;
//加载地理编码插件
mapObj.plugin(["AMap.Geocoder"], function() { //加载地理编码插件
geocoder = new AMap.Geocoder({
radius: 1000, //以已知坐标为中心点,radius为半径,返回范围内兴趣点和道路信息
extensions: "all" //返回地址描述以及附近兴趣点和道路信息,默认“base”
});
//返回地理编码结果
geocoder.on("complete", geocoder_CallBack);
//逆地理编码
geocoder.getAddress(new AMap.LngLat(116.359119, 39.972121));
});
```
### getLocation
将地址信息转化为高德经纬度坐标信息
#### Parameters
- `keyword` **String** 关键字
- `cbk` **GeocoderCallback** 回调函数
### setCity
地理编码时,设置地址描述所在城市
#### Parameters
- `city` **String** 所在城市
### getAddress
将高德经纬度坐标信息转化为结构化的地址信息
#### Parameters
- `location` **(LngLat \| Array<LngLat>)** 给定坐标
- `cbk` **ReGeocoderCallback** 回调函数
## GeocoderCallback
Geocoder getLocation 回调函数
Type: Function
### Parameters
- `status` **string** 当status为complete时,result为GeocodeResult;当status为error时,result为错误信息info;当status为no_data时,代表检索返回0结果
- `result` **(info | GeocodeResult)** 地理编码 [详查rest文档][106]
## ReGeocoderCallback
Geocoder getAddress 回调函数
Type: Function
### Parameters
- `status` **string** 当status为complete时,result为GeocodeResult;当status为error时,result为错误信息info;当status为no_data时,代表检索返回0结果
- `result` **(info | ReGeocodeResult)** 逆地理编码 [详查rest文档][107]
## convertFrom
地球上同一个地理位置的经纬度,在不同的坐标系中,会有少于偏移,国内目前常见的坐标系主要分为三种: </br>
1\. 地球坐标系——WGS84:常见于 GPS 设备,Google 地图等国际标准的坐标体系。 </br>
2\. 火星坐标系——GCJ-02:中国国内使用的被强制加密后的坐标体系,高德坐标就属于该种坐标体系。 </br>
3\. 百度坐标系——BD-09:百度地图所使用的坐标体系,是在火星坐标系的基础上又进行了一次加密处理。 </br>
因此在使用不同坐标系前,我们需要使用 AMap.convertFrom() 方法将这些非高德坐标系进行转换。 </br>
[相关示例][108]
### Parameters
- `lnglat` **LngLat** 需要转换的坐标或者坐标组
- `type` **String** 坐标类型 (optional, default `'gps'`)
- `cbk` **Function?** 转换成功后的回调函数
### Examples
```javascript
var gps = [116.3, 39.9];
AMap.convertFrom(gps, 'gps', function (status, result) {
if (result.info === 'ok') {
var lnglats = result.locations; // Array.<LngLat>
}
});
```
FILE:references/api/geolocation.md
## 定位
用于进行城市定位或者精确定位的插件类型
## Geolocation
**Extends AMap.Control**
AMap.Geolocation 定位服务插件。融合了浏览器定位、高精度IP定位、安卓定位sdk辅助定位等多种手段,提供了获取当前准确位置、获取当前城市信息、持续定位(浏览器定位)等功能。用户可以通过两种当时获得定位的成败和结果,一种是在 getCurrentPosition的时候传入回调函数来处理定位结果,一种是通过事件监听来取得定位结果。
### Parameters
- `options` **GeolocationOptions** 初始化参数
- `options.position` **string** 悬停位置,默认为"RB",即右下角
- `options.offset` **\[number, number]** 缩略图距离悬停位置的像素距离,如[2,2]
- `options.borderColor` **string** 按钮边框颜色值,同CSS,如'silver'
- `options.borderRadius` **string** 按钮圆角边框值,同CSS,如'5px'
- `options.buttonSize` **string** 箭头按钮的像素尺寸,同CSS,如'12px'
- `options.convert` **boolean** 是否将定位结果转换为高德坐标
- `options.enableHighAccuracy` **boolean** 进行浏览器原生定位的时候是否尝试获取较高精度,可能影响定位效率,默认为false
- `options.timeout` **number** 定位的超时时间,毫秒
- `options.maximumAge` **number** 浏览器原生定位的缓存时间,毫秒
- `options.showButton` **boolean** 是否显示定位按钮,默认为true
- `options.showCircle` **boolean** 是否显示定位精度圆,默认为true
- `options.showMarker` **boolean** 是否显示定位点,默认为true
- `options.markerOptions` **MarkerOptions** 定位点的样式
- `options.circleOptions` **CircleOptions** 定位圆的样式
- `options.panToLocation` **boolean** 定位成功后是否自动移动到响应位置
- `options.zoomToAccuracy` **boolean** 定位成功后是否自动调整级别
- `options.GeoLocationFirst` **boolean** 优先使用H5定位,默认移动端为true,PC端为false
- `options.noIpLocate` **number** 是否禁用IP精确定位,默认为0,0:都用 1:手机上不用 2:PC上不用 3:都不用
- `options.noGeoLocation` **number** 是否禁用浏览器原生定位,默认为0,0:都用 1:手机上不用 2:PC上不用 3:都不用
- `options.useNative` **boolean** 是否与高德定位SDK能力结合,需要同时使用安卓版高德定位sdk,否则无效
- `options.getCityWhenFail` **boolean** 定位失败之后是否返回基本城市定位信息
- `options.needAddress` **boolean** 是否需要将定位结果进行逆地理编码操作
- `options.extensions` **string** 是否需要详细的逆地理编码信息,默认为'base'只返回基本信息,可选'all'
### getCurrentPosition
获取 用户的精确位置,有失败几率
#### Parameters
- `callback` **GeolocationCallBack** 定位回调函数,成功或者失败均会回调
### getCityInfo
根据用户 IP 获取 用户所在城市信息
#### Parameters
- `callback` **GeolocationCallBack**
## GeolocationCallBack
Geolocation插件的定位回调函数
Type: Function
### Parameters
- `status` **string** 'complete' 或者 'error'
- `result` **GeolocationResult** 定位结果
## GeolocationResult
浏览器定位的定位结果,定位的过程和失败信息可以从 message 字段中获取
Type: Object
### Properties
- `position` **LngLat** 定位到的经纬度位置
- `accuracy` **number** 定位精度,米
- `location_type` **number** 定位的类型,ip/h5/sdk/ipcity
- `message` **number** 定位过程的信息,用于排查定位失败原因
- `isConverted` **number** 是否已经转换为高德坐标
- `info` **number** 'SUCCESS' 或者 'PERMISSION_DENIED' 或者 'TIME_OUT' 或者 'POSITION_UNAVAILABLE'
- `addressComponent` **number** needAddress的时候返回,结构化地址信息
- `formattedAddress` **number** needAddress的时候返回,规范地址
- `pois` **number** needAddress的时候返回,定位点附近的POI信息
- `roads` **number** needAddress的时候返回,定位点附近的道路信息
- `crosses` **number** needAddress的时候返回,定位点附近的交叉口信息
## CitySearch
**Extends AMap.Event**
AMap.CitySearch 根据IP返回对应城市信息,提供根据输入IP或自动获取IP获取对应城市信息功能。
用户可以通过自定义回调函数取回并显示[查询结果][139]。
若服务请求失败,系统将返回[错误信息][140]。
### getLocalCity
自动获取用户IP,回调返回当前用户所在城市
当status为complete时,result为CitySearchResult;
当status为error时,result为错误信息info;
当status为no_data时,代表检索返回0结果
#### Parameters
- `CitySearchCallback` **function** 查询的回调函数
- `cbk` **function (status: String, result: info)** 回调函数
### getCityByIp
根据输入IP地址返回对应城市信息,status同上
#### Parameters
- `ip` **String** IP地址
- `CitySearchCallback` **function (status: String, result: info)** 回调函数
FILE:references/api/info-window.md
## 信息窗体
用于在地图上展示复杂的说明性信息的类型
## InfoWindow
**Extends OverlayDOM**
信息窗体,地图仅可同时展示一个信息窗体,推荐为信息窗体通过样式显示设置尺寸。 \* // [亲手试一试][79]
### Parameters
- `opts` **InfoOptions** 信息窗体参数
- `opts.isCustom` **boolean** 是否自定义窗体。设为true时,信息窗体外框及内容完全按照content所设的值添加(默认为false,即在系统默认的信息窗体外框中显示content内容)
- `opts.autoMove` **boolean** 是否自动调整窗体到视野内(当信息窗体超出视野范围时,通过该属性设置是否自动平移地图,使信息窗体完全显示)
- `opts.avoid` **Array<number>** autoMove 为 true 时,自动平移到视野内后的上右下左的避让宽度。默认值:[20, 20, 20, 20]
- `opts.closeWhenClickMap` **boolean** 控制是否在鼠标点击地图后关闭信息窗体,默认false,鼠标点击地图后不关闭信息窗体
- `opts.content` **(String \| HTMLElement)** 显示内容,可以是HTML要素字符串或者HTMLElement对象, [自定义窗体示例][81]
- `opts.size` **Size** 信息窗体尺寸(isCustom为true时,该属性无效)
- `opts.anchor` **string** 信息窗体锚点。默认值:'bottom-center'。可选值:'top-left'|'top-center'|'top-right'|'middle-left'|'center'|'middle-right'|'bottom-left'|'bottom-center'|'bottom-right'
- `opts.offset` **(Vector | Pixel)** 信息窗体显示位置偏移量。默认基准点为信息窗体的底部中心。默认值: [0, 0]
- `opts.position` **(Vector | LngLat)** 信息窗体显示基点位置
### Examples
```javascript
var infoWindow = new AMap.InfoWindow({
content: '信息窗体',
anchor: 'bottom-center',
});
// 在地图上打开信息窗体
infoWindow.open(map, [116.397389,39.909466]);
```
### open
打开信息窗体
#### Parameters
- `map` **Map**
- `position` **Vector2**
- `height` **number**
### getIsOpen
获取信息窗体是否打开
Returns **boolean**
### setSize
设置信息窗体大小(isCustom为false时有效)
#### Parameters
- `size` **(Size | Vector2)**
### setContent
获取信息窗体大小
#### Parameters
- `content` **(HTMLElement \| string)**
### setAnchor
设置信息窗体锚点 默认值:'bottom-center'。可选值:'top-left'|'top-center'|'top-right'|'middle-left'|'center'|'middle-right'|'bottom-left'|'bottom-center'|'bottom-right'
#### Parameters
- `anchor` **string**
### getExtData
获取用户自定义属性
Returns **(any | undefined)**
### setExtData
设置用户自定义属性
#### Parameters
- `extData`
FILE:references/api/layers-custom.md
## 自有数据图层
用于加载展示开发者自己拥有的数据或者图像的图层类型
## HeatMap
热力图,基于第三方heatmap.js实现,以特殊高亮的形式显示数据密集程度。根据密集程度的不同,图上会呈现不同的颜色,以直观的形式展现数据密度。API引用了heatmap.js最新版本v2.0,v2.0基于新的渲染模型,具有更高的渲染效率和更强的性能。支持chrome、firefox、safari、ie9及以上浏览器。
### Parameters
- `map` **Map** 要叠加热力图的地图对象
- `opts` **HeatMapOptions** 热力图属性配置
- `opts.radius` **number** 热力图中单个点的半径,默认:30,单位:pixel
- `opts.gradient` **object** 热力图的渐变区间,热力图按照设置的颜色及间隔显示热力图,例{0.4:'rgb(0, 255, 255)',0.85:'rgb(100, 0, 255)',},其中 key 表示间隔位置,取值范围: [0,1],value 为颜色值。默认:heatmap.js标准配色方案
- `opts.opacity` **array** 热力图透明度区间数组,取值范围[0,1],0表示完全透明,1表示不透明,默认:[0,1]
- `opts.zooms` **array** 支持的缩放级别范围,取值范围[3-20],默认:[3,20]
- `opts.visible` **boolean** 是否可见
- `opts.zIndex` **number** 热力图层在地图上的叠加顺序,默认 130
- `opts.3d` **HeatMap3DOptions** 3D热力图属性
- `opts.3d.heightScale` **number** 高度缩放因子,表示在单位高度上的缩放比例, 默认为 1
- `opts.3d.heightBezier` **array** 影响高度平滑度的贝塞尔曲线因子,默认 [0.5, 0, 1, 0.5],
- `opts.3d.gridSize` **number** 取样精度,越小越平滑,越大性能越高
### Examples
```javascript
var heatmap;
var points = [
{"lng":116.191031,"lat":39.988585,"count":10},
{"lng":116.389275,"lat":39.925818,"count":11},
{"lng":116.287444,"lat":39.810742,"count":12},
{"lng":116.481707,"lat":39.940089,"count":13},
{"lng":116.410588,"lat":39.880172,"count":14},
{"lng":116.394816,"lat":39.91181,"count":15},
{"lng":116.416002,"lat":39.952917,"count":16},
];
// 加载热力图插件
map.plugin(["AMap.HeatMap"],function(){
// 在地图对象叠加热力图
heatmap = new AMap.Heatmap({map:map});
// 设置热力图数据集
heatmap.setDataSet({data:points,max:100});
});
```
### getMap
获取热力图叠加地图对象
Returns **Map**
### setMap
设置热力图要叠加的地图实例,也可以在Map中的layers属性中设置为默认显示的图层
#### Parameters
- `map` **Map** 地图实例
### getOptions
获取热力图的属性信息
Returns **HeatMapOptions**
### setOptions
设置热力图属性,请参考 HeatMapOptions 列表中的说明
#### Parameters
- `options` **HeatMapOptions** 热力图配置
### getDataSet
输出热力图的数据集,数据结构同setDataSet中的数据集
Returns **object**
### setDataSet
设置热力图展现的数据集,dataset数据集格式为:
{
max: Number 权重的最大值,
data: Array 坐标数据集
},
其中max不填则取数据集count最大值
例: {
max: 100,
data: [{lng: 116.405285, lat: 39.904989, count: 65},{}, …]
}
也可以通过url来加载数据,格式为
{
data:jsonp格式数据的服务地址URL,
dataParser: 数据格式转换function //当jsonp返回结果和官方结构不一致的时候,用户可以传递一个函数用来进行数据格式转换;
}
例:
{
data:'[http://abc.com/jsonp.js'][61],
dataParser:function(data){
return doSomthing(data);//返回的对象结果应该与上面例子的data字段结构相同
}
}
#### Parameters
- `dataset` **object** 数据集
### addDataPoint
向热力图数据集中添加坐标点,count不填写时默认:1
#### Parameters
- `longitude` **string** 经度
- `latitude` **string** 纬度
- `count` **number** 权重
### getzIndex
获得热力图层叠加层级
Returns **number**
### setzIndex
设置热力图层叠加层级
#### Parameters
- `zIndex` **number** 热力图层叠加层级
### show
显示热力图
### hide
隐藏热力图
## VectorLayer
**Extends \_Layer.CoreVectorLayer**
### add
添加矢量覆盖物到集合中,不支持添加重复的覆盖物
#### Parameters
- `vectors` **(VectorOverlay | Array<VectorOverlay>)** 矢量覆盖物或矢量覆盖物数组
### remove
删除矢量覆盖物
#### Parameters
- `vectors` **(VectorOverlay | Array<VectorOverlay>)** 矢量覆盖物或矢量覆盖物数组
### show
显示图层
### hide
隐藏图层
### has
判断传入的矢量覆盖物实例是否在VectorLayer这中
#### Parameters
- `vector` **VectorOverlay**
Returns **boolean**
### clear
清空 VectorLayer
### setOptions
批量修改矢量覆盖物属性(包括线样式、样色等等)
#### Parameters
- `opt` **Object**
### query
根据经纬度查询矢量覆盖物信息
#### Parameters
- `geometry` **LngLatLike**
Returns **(VectorOverlay | undefined)** vector 矢量覆盖物
### getBounds
获取 VectorOverlay 所有覆盖物显示的范围
Returns **(Bounds \| undefined)** 经纬度范围值
## VectorLayer
**Extends \_Layer.CoreVectorLayer**
### Parameters
- `opts` **Object**
- `opts.visible` **boolean** 是否显示 (optional, default `true`)
- `opts.zIndex` **number** 是否显示 (optional, default `110`)
### Examples
```javascript
var layer = new AMap.VectorLayer();
map.add(layer);
var circle = new AMap.circle({center: [116.4, 39.9], radius:1000});
layer.add(circle);
```
### add
添加矢量覆盖物到集合中,不支持添加重复的覆盖物
#### Parameters
- `vectors` **(VectorOverlay | Array<VectorOverlay>)** 矢量覆盖物或矢量覆盖物数组
### remove
删除矢量覆盖物
#### Parameters
- `vectors` **(VectorOverlay | Array<VectorOverlay>)** 矢量覆盖物或矢量覆盖物数组
### show
显示图层
### hide
隐藏图层
### has
判断传入的矢量覆盖物实例是否在VectorLayer这中
#### Parameters
- `vector` **VectorOverlay**
Returns **boolean**
### clear
清空 VectorLayer
### setOptions
批量修改矢量覆盖物属性(包括线样式、样色等等)
#### Parameters
- `opt` **Object**
### query
根据经纬度查询矢量覆盖物信息
#### Parameters
- `geometry` **LngLatLike**
Returns **(VectorOverlay | undefined)** vector 矢量覆盖物
### getBounds
获取 VectorOverlay 所有覆盖物显示的范围
Returns **(Bounds \| undefined)** 经纬度范围值
## LabelsLayer
标注层
### Parameters
- `opts` **LabelsLayerOptions** 标注层参数
- `opts.visible` **boolean** 标注层是否可见,默认值:true
- `opts.zIndex` **number** 标注层与其它图层的叠加顺序,默认值:120
- `opts.opacity` **number** 标注层透明度
- `opts.collision` **boolean** 标注层内的标注是否避让
- `opts.allowCollision` **boolean** 标注层内的标注是否允许其它标注层对它避让
- `opts.zooms` **\[number, number]** 标注层展示层级范围
### Examples
```javascript
// 创建一个标注层实例
var labelsLayer = new AMap.LabelsLayer({
collision: true,
opacity: 1,
zIndex: 120,
allowCollision: true,
});
// 将标注层添加到地图上
map.add(labelsLayer);
```
### getCollision
获取标注层是否支持内部标注避让
Returns **any**
### setCollision
设置标注层是否支持内部标注避让
#### Parameters
- `collision` **boolean** 默认值: true
### getAllowCollision
获取标注层是否允许其它层标注避让
Returns **boolean**
### setAllowCollision
设置标注层是否允许其它层标注避让,开启该功能可实现地图标注对 LabelMarker 的避让,[相关示例][63]
#### Parameters
- `allowCollision` **boolean**
### getOpacity
获取标注层透明度
Returns **number**
### setOpacity
设置标注层透明度
#### Parameters
- `opacity` **number**
### getZooms
获取标注层显示层级范围
Returns **any**
### setZooms
设置标注层显示层级范围
#### Parameters
- `zooms` **\[number]**
### getzIndex
获取标注层叠加顺序
Returns **number**
### setzIndex
设置标注层叠加顺序
#### Parameters
- `zIndex` **number**
### add
将 labelMarker 添加到标注层上
#### Parameters
- `labelMarkers` **Array<LabelMarker>** 可添加单个标注或标注数组
### remove
将 labelMarker 从标注层上移除
#### Parameters
- `labelMarkers` **(LabelMarker \| Array<LabelMarker>)** 可移除单个标注或标注数组
### clear
清空标注层上的标注
### show
显示标注层
### hide
隐藏标注层
### getAllOverlays
获取标注层内的所有标注对象
Returns **Array<any>**
## CustomLayer
**Extends \_Layer.CoreCustomLayer**
### Parameters
- `canvas`
- `opts`
### getOptions
获取图层参数信息
Returns **Object** 图层参数信息
### getzIndex
获取图层层级
Returns **Number** zIndex 图层层级
### setzIndex
设置图层层级,数字越大图层层级越高
#### Parameters
- `zIndex` **Number** 图层层级值
### setzIndex
设置图层层级
#### Parameters
- `zIndex` **number** 图层层级
### getOpacity
获取图层透明度
Returns **Number** opacity 图层透明度
### setOpacity
设置图层透明度,范围 [0 ~ 1]
#### Parameters
- `opacity` **Number** 图层透明度
### getZooms
获取该图层可显示的级别范围,默认取值范围为[2-20]
Returns **\[Number, Number]** 缩放范围
### setZooms
获取该图层可显示的级别范围
#### Parameters
- `zooms` **\[Number, Number]** 缩放范围
### show
设置图层可见
### hide
设置图层隐藏
### setMap
添加到地图上
#### Parameters
- `地图实例对象` **Map**
## CustomLayer
**Extends Layer**
自定义图层是一种完全由开发者来指定绘制方法的图层 </br>
[相关示例][65]
### Parameters
- `canvas` **HTMLCanvasElement** canvas 对象
- `opts` **CustomLayerOption** 默认图层参数
- `opts.render` **Function** 绘制函数,初始化完成时候,开发者需要给该图层设定render方法, </br>
该方法需要实现图层的绘制,API会在合适的时机自动调用该方法
- `opts.zooms` **\[Number, Number]** 图层缩放等级范围,默认 [2, 20] (optional, default `[2,20]`)
- `opts.opacity` **Number** 图层透明度,默认为 1 (optional, default `1`)
- `opts.visible` **Boolean** 图层是否可见,默认为 true (optional, default `true`)
- `opts.zIndex` **Number** 图层的层级,默认为 120 (optional, default `120`)
- `opts.alwaysRender` **Boolean** 是否主动 (optional, default `false`)
### Examples
```javascript
var cLayer = new AMap.CustomLayer(canvas, {
zooms: [2, 18],
zIndex: 120,
render() {
// 对 canvas 进行绘制
}
})
```
### getOptions
获取图层参数信息
Returns **Object** 图层参数信息
### getzIndex
获取图层层级
Returns **Number** zIndex 图层层级
### setzIndex
设置图层层级,数字越大图层层级越高
#### Parameters
- `zIndex` **Number** 图层层级值
### setzIndex
设置图层层级
#### Parameters
- `zIndex` **number** 图层层级
### getOpacity
获取图层透明度
Returns **Number** opacity 图层透明度
### setOpacity
设置图层透明度,范围 [0 ~ 1]
#### Parameters
- `opacity` **Number** 图层透明度
### getZooms
获取该图层可显示的级别范围,默认取值范围为[2-20]
Returns **\[Number, Number]** 缩放范围
### setZooms
获取该图层可显示的级别范围
#### Parameters
- `zooms` **\[Number, Number]** 缩放范围
### show
设置图层可见
### hide
设置图层隐藏
### setMap
添加到地图上
#### Parameters
- `地图实例对象` **Map**
## Flexible
**Extends TileLayer**
灵活切片图层,继承自AMap.TileLayer,开发者可通过构造时传入给其传入createTile字段来指定每一个切片的内容 </br>
[相关示例][67]
### Parameters
- `opts` **FlexibleLayerOptions**
- `opts.cacheSize` **Number** 缓存瓦片数量
- `opts.createTile` **function (x, y, z, success, fail)** 由开发者实现,由API自动调用,xyz分别为切片横向纵向编号和层级,切片大小
256。假设每次创建的贴片为A(支持img或者canvas),当创建或者获取成功时请回调success(A),不需要显示或者失败时请回调fail()
- `opts.zooms` **\[Number, Number]** 支持的缩放级别范围,默认范围 [2-30] (optional, default `[2,30]`)
- `opts.opacity` **Number** 透明度,默认 1 (optional, default `1`)
- `opts.visible` **Boolean** 是否显示,默认 true (optional, default `true`)
- `opts.zIndex` **Number** 图层叠加的顺序值,1 表示最底层。默认 zIndex:4 (optional, default `4`)
- `opts.tileSize` **Number** 切片大小,取值: </br>
256,表示切片大小为256_256, </br>
128,表示切片大小为128_128, </br>
64,表示切片大小为64\*64。默认值为256 (optional, default `256`)
### getOptions
获取图层参数信息
Returns **Object** 图层参数信息
### getzIndex
获取图层层级
Returns **Number** zIndex 图层层级
### setzIndex
设置图层层级,数字越大图层层级越高
#### Parameters
- `zIndex` **Number** 图层层级值
### getOpacity
获取图层透明度
Returns **Number** opacity 图层透明度
### setOpacity
设置图层透明度,范围 [0 ~ 1]
#### Parameters
- `opacity` **Number** 图层透明度
### getZooms
获取该图层可显示的级别范围,默认取值范围为[2-30]
Returns **\[Number, Number]** 缩放范围
### setZooms
获取该图层可显示的级别范围
#### Parameters
- `zooms` **\[Number, Number]** 缩放范围
### show
设置图层可见
### hide
设置图层隐藏
### destroy
销毁图层
## ImageLayer
**Extends Layer**
图片图层类,用户可以将一张静态图片作为图层添加在地图上,图片图层会随缩放级别而自适应缩放。 </br>
[相关示例][68]
### Parameters
- `opts` **ImageLayerOptions** 传入默认参数列表
- `opts.url` **String** 图片地址链接
- `opts.zooms` **\[Number, Number]** 图层缩放等级范围,默认 [2, 30] (optional, default `[2,30]`)
- `opts.bounds` **(\[Number, Number, Number, Number] | Bounds)** 图片的范围大小经纬度,如果传递数字数组类型: [minlng,minlat,maxlng,maxlat]
- `opts.opacity` **Number** 图层透明度,默认为 1 (optional, default `1`)
- `opts.visible` **Boolean** 图层是否可见,默认为 true (optional, default `true`)
- `opts.zIndex` **Number** 图层的层级,默认为 6 (optional, default `6`)
### Examples
```javascript
var imageLayer = new AMap.ImageLayer({
url: 'https://amappc.cn-hangzhou.oss-pub.aliyun-inc.com/lbs/static/img/dongwuyuan.jpg',
bounds: new AMap.Bounds(
[116.327911, 39.939229],
[116.342659, 39.946275]
),
zooms: [10, 18]
});
```
### getImageUrl
获取图片的地址
### setImageUrl
设置图片的地址
#### Parameters
- `url` **String** 图片地址
### getBounds
获取 ImageLayer显示的范围
Returns **Bounds** 经纬度范围值
### setBounds
设置 ImageLayer显示的范围
### getOptions
获取图层参数信息
Returns **object** 图层参数信息
### getzIndex
获取图层层级
Returns **Number** zIndex 图层层级
### setzIndex
设置图层层级,数字越大图层层级越高
#### Parameters
- `zIndex` **Number** 图层层级值
### getOpacity
获取图层透明度
Returns **Number** opacity 图层透明度
### setOpacity
设置图层透明度,范围 [0 ~ 1]
#### Parameters
- `opacity` **Number** 图层透明度
### getZooms
获取该图层可显示的级别范围,默认取值范围为[2-20]
Returns **\[number, number]** 缩放范围
### setZooms
获取该图层可显示的级别范围
#### Parameters
- `zooms` **\[number, number]** 缩放范围
### show
设置图层可见
### hide
设置图层隐藏
## CanvasLayer
**Extends ImageLayer**
Canvas图层类,用户可以将一个 Canvas 作为图层添加在地图上,Canvas图层会随缩放级别而自适应缩放。 </br>
[相关示例][69]
### Parameters
- `opts` **ImageLayerOptions** 传入默认参数列表
- `opts.canvas` **HTMLCanvasElement** Canvas DOM 对象
- `opts.zooms` **\[Number, Number]** 图层缩放等级范围,默认 [2, 30] (optional, default `[2,30]`)
- `opts.bounds` **(\[Number, Number, Number, Number] | Bounds)** canvas 的范围大小经纬度, 如果传递数字数组类型: [minlng,minlat,maxlng,maxlat]
- `opts.opacity` **Number** 图层透明度,默认为 1 (optional, default `1`)
- `opts.visible` **Boolean** 图层是否可见,默认为 true (optional, default `true`)
- `opts.zIndex` **Number** 图层的层级,默认为 6 (optional, default `6`)
### setCanvas
修改显示的Canvas
#### Parameters
- `canvas` **HTMLCanvasElement**
### getElement
返回 Canvas 对象
Returns **HTMLCanvasElement** canvas 对象
### getBounds
返回 canvas 范围的经纬度
Returns **Bounds** 范围经纬度
### getBounds
当canvas的内容发生改变是用于刷新图层,3D视图下调用,2D视图不需要调用
### setBounds
设置 CanvasLayer 显示的范围
### getOptions
获取图层参数信息
Returns **object** 图层参数信息
### getzIndex
获取图层层级
Returns **number** zIndex 图层层级
### setzIndex
设置图层层级,数字越大图层层级越高
#### Parameters
- `zIndex` **number** 图层层级值
### getOpacity
获取图层透明度
Returns **number** opacity 图层透明度
### setOpacity
设置图层透明度,范围 [0 ~ 1]
#### Parameters
- `opacity` **number** 图层透明度
### getZooms
获取该图层可显示的级别范围,默认取值范围为[2-20]
Returns **\[number, number]** 缩放范围
### setZooms
获取该图层可显示的级别范围
#### Parameters
- `zooms` **\[number, number]** 缩放范围
### show
设置图层可见
### hide
设置图层隐藏
## GLCustomLayer
3d 自定义图层
### Parameters
- `opts` **GlCustomLayerOptions**
- `opts.init` **Function** 初始化的时候,开发者可以在这个函数参数里面获取 gl 上下文,进行一些初始化的操作。
- `opts.render` **Function** 绘制函数,初始化完成时候,开发者需要给该图层设定render方法, </br>
该方法需要实现图层的绘制,API会在合适的时机自动调用该方法
- `opts.zooms` **\[Number, Number]** 图层缩放等级范围,默认 [2, 20] (optional, default `[2,20]`)
- `opts.opacity` **Number** 图层透明度,默认为 1 (optional, default `1`)
- `opts.visible` **Boolean** 图层是否可见,默认为 true (optional, default `true`)
- `opts.zIndex` **Number** 图层的层级,默认为 120 (optional, default `10`)
### Examples
```javascript
var glCustomLayer = new GLCustomLayer({
init: function(gl){
// init shader or sth...
},
render: function(gl, state){
// render every frame
},
});
```
### getMap
获取GLCustomLayer所属地图实例
Returns **(Map | null)**
### getzIndex
获取GLCustomLayer叠加顺序
Returns **number**
### setzIndex
设置GLCustomLayer叠加顺序
#### Parameters
- `zIndex` **number** 叠加值
Returns **void**
### getOpacity
获取GLCustomLayer透明度
Returns **number**
### setOpacity
设置GLCustomLayer透明度
#### Parameters
- `opacity` **number** 透明度
Returns **void**
### getZooms
获取GLCustomLayer显示层级范围
Returns **number**
### setZooms
设置GLCustomLayer显示层级范围
#### Parameters
- `zooms` **Vector** 显示层级范围,默认[3, 20]
Returns **number**
### show
显示GLCustomLayer
Returns **void**
### hide
隐藏GLCustomLayer
Returns **void**
FILE:references/api/layers-official.md
## 高德官方图层
由高德官方提供数据或图像的地图图层
## TileLayer
**Extends Layer**
切片图层类,该类为基础类。 </br>
[相关示例][37]
### Parameters
- `opts` **TileLayerOptions**
- `opts.tileUrl` **String** 切片取图地址
如:'[https://abc{0,1,2,3}.amap.com/tile?x=\[x\]&y=\[y\]&z=\[z\]][39]'
[x]、[y]、[z]分别替代切片的xyz。
- `opts.zooms` **\[Number, Number]** 支持的缩放级别范围,默认范围 [2-30] (optional, default `[2,30]`)
- `opts.dataZooms` **\[Number, Number]** 数据支持的缩放级别范围,默认范围 [2-30] (optional, default `[2,30]`)
- `opts.opacity` **Number** 透明度,默认 1 (optional, default `1`)
- `opts.visible` **Boolean** 是否显示,默认 true (optional, default `true`)
- `opts.zIndex` **Number** 图层叠加的顺序值,1 表示最底层。默认 zIndex:4 (optional, default `4`)
- `opts.tileSize` **Number** 切片大小,取值:
256,表示切片大小为256_256,
128,表示切片大小为128_128,
64,表示切片大小为64\*64。默认值为256 (optional, default `256`)
### setTileUrl
设置图层的取图地址
#### Parameters
- `url` **String** 瓦片图地址
### reload
重新加载图层资源,重新渲染
### getOptions
获取图层参数信息
Returns **Object** 图层参数信息
### getzIndex
获取图层层级
Returns **Number** zIndex 图层层级
### setzIndex
设置图层层级,数字越大图层层级越高
#### Parameters
- `zIndex` **Number** 图层层级值
### getOpacity
获取图层透明度
Returns **Number** opacity 图层透明度
### setOpacity
设置图层透明度,范围 [0 ~ 1]
#### Parameters
- `opacity` **Number** 图层透明度
### getZooms
获取该图层可显示的级别范围,默认取值范围为[2-30]
Returns **\[Number, Number]** 缩放范围
### setZooms
获取该图层可显示的级别范围
#### Parameters
- `zooms` **\[Number, Number]** 缩放范围
### show
设置图层可见
### hide
设置图层隐藏
## Traffic
**Extends TileLayer**
实时交通图层类,继承自TileLayer。 </br>
[相关示例][40]
### Parameters
- `opts` **TrafficLayerOptions**
- `opts.autoRefresh` **Boolean** 是否自动更新数据,默认开启
- `opts.interval` **Number** 自动更新数据的间隔毫秒数,默认 180ms
- `opts.zooms` **\[Number, Number]** 支持的缩放级别范围,默认范围 [2-30] (optional, default `[2,30]`)
- `opts.opacity` **Number** 透明度,默认 1 (optional, default `1`)
- `opts.visible` **Boolean** 是否显示,默认 true (optional, default `true`)
- `opts.zIndex` **Number** 图层叠加的顺序值,1 表示最底层。默认 zIndex:4 (optional, default `4`)
- `opts.tileSize` **Number** 切片大小,取值:
256,表示切片大小为256_256,
128,表示切片大小为128_128,
64,表示切片大小为64\*64。默认值为256 (optional, default `256`)
### stopFresh
停止自动更新数据
### getOptions
获取图层参数信息
Returns **Object** 图层参数信息
### getzIndex
获取图层层级
Returns **Number** zIndex 图层层级
### setzIndex
设置图层层级,数字越大图层层级越高
#### Parameters
- `zIndex` **Number** 图层层级值
### getOpacity
获取图层透明度
Returns **Number** opacity 图层透明度
### setOpacity
设置图层透明度,范围 [0 ~ 1]
#### Parameters
- `opacity` **Number** 图层透明度
### getZooms
获取该图层可显示的级别范围,默认取值范围为[2-30]
Returns **\[Number, Number]** 缩放范围
### setZooms
获取该图层可显示的级别范围
#### Parameters
- `zooms` **\[Number, Number]** 缩放范围
### show
设置图层可见
### hide
设置图层隐藏
## Satellite
**Extends TileLayer**
### Parameters
- `opts` (optional, default `satelliteDefaultOptions`)
### getOptions
获取图层参数信息
Returns **Object** 图层参数信息
### getzIndex
获取图层层级
Returns **Number** zIndex 图层层级
### setzIndex
设置图层层级,数字越大图层层级越高
#### Parameters
- `zIndex` **Number** 图层层级值
### getOpacity
获取图层透明度
Returns **Number** opacity 图层透明度
### setOpacity
设置图层透明度,范围 [0 ~ 1]
#### Parameters
- `opacity` **Number** 图层透明度
### getZooms
获取该图层可显示的级别范围,默认取值范围为[2-30]
Returns **\[Number, Number]** 缩放范围
### setZooms
获取该图层可显示的级别范围
#### Parameters
- `zooms` **\[Number, Number]** 缩放范围
### show
设置图层可见
### hide
设置图层隐藏
### destroy
销毁图层
## Satellite
**Extends TileLayer**
### Parameters
- `opts` (optional, default `satelliteDefaultOptions`)
### getOptions
获取图层参数信息
Returns **Object** 图层参数信息
### getzIndex
获取图层层级
Returns **Number** zIndex 图层层级
### setzIndex
设置图层层级,数字越大图层层级越高
#### Parameters
- `zIndex` **Number** 图层层级值
### getOpacity
获取图层透明度
Returns **Number** opacity 图层透明度
### setOpacity
设置图层透明度,范围 [0 ~ 1]
#### Parameters
- `opacity` **Number** 图层透明度
### getZooms
获取该图层可显示的级别范围,默认取值范围为[2-30]
Returns **\[Number, Number]** 缩放范围
### setZooms
获取该图层可显示的级别范围
#### Parameters
- `zooms` **\[Number, Number]** 缩放范围
### show
设置图层可见
### hide
设置图层隐藏
### destroy
销毁图层
## Satellite
**Extends TileLayer**
### Parameters
- `opts` (optional, default `satelliteDefaultOptions`)
### getOptions
获取图层参数信息
Returns **Object** 图层参数信息
### getzIndex
获取图层层级
Returns **Number** zIndex 图层层级
### setzIndex
设置图层层级,数字越大图层层级越高
#### Parameters
- `zIndex` **Number** 图层层级值
### getOpacity
获取图层透明度
Returns **Number** opacity 图层透明度
### setOpacity
设置图层透明度,范围 [0 ~ 1]
#### Parameters
- `opacity` **Number** 图层透明度
### getZooms
获取该图层可显示的级别范围,默认取值范围为[2-30]
Returns **\[Number, Number]** 缩放范围
### setZooms
获取该图层可显示的级别范围
#### Parameters
- `zooms` **\[Number, Number]** 缩放范围
### show
设置图层可见
### hide
设置图层隐藏
### destroy
销毁图层
## Satellite
**Extends TileLayer**
### Parameters
- `opts` (optional, default `satelliteDefaultOptions`)
### getOptions
获取图层参数信息
Returns **Object** 图层参数信息
### getzIndex
获取图层层级
Returns **Number** zIndex 图层层级
### setzIndex
设置图层层级,数字越大图层层级越高
#### Parameters
- `zIndex` **Number** 图层层级值
### getOpacity
获取图层透明度
Returns **Number** opacity 图层透明度
### setOpacity
设置图层透明度,范围 [0 ~ 1]
#### Parameters
- `opacity` **Number** 图层透明度
### getZooms
获取该图层可显示的级别范围,默认取值范围为[2-30]
Returns **\[Number, Number]** 缩放范围
### setZooms
获取该图层可显示的级别范围
#### Parameters
- `zooms` **\[Number, Number]** 缩放范围
### show
设置图层可见
### hide
设置图层隐藏
### destroy
销毁图层
## Satellite
**Extends TileLayer**
### Parameters
- `opts` (optional, default `satelliteDefaultOptions`)
### getOptions
获取图层参数信息
Returns **Object** 图层参数信息
### getzIndex
获取图层层级
Returns **Number** zIndex 图层层级
### setzIndex
设置图层层级,数字越大图层层级越高
#### Parameters
- `zIndex` **Number** 图层层级值
### getOpacity
获取图层透明度
Returns **Number** opacity 图层透明度
### setOpacity
设置图层透明度,范围 [0 ~ 1]
#### Parameters
- `opacity` **Number** 图层透明度
### getZooms
获取该图层可显示的级别范围,默认取值范围为[2-30]
Returns **\[Number, Number]** 缩放范围
### setZooms
获取该图层可显示的级别范围
#### Parameters
- `zooms` **\[Number, Number]** 缩放范围
### show
设置图层可见
### hide
设置图层隐藏
### destroy
销毁图层
## Satellite
**Extends TileLayer**
### Parameters
- `opts` (optional, default `satelliteDefaultOptions`)
### getOptions
获取图层参数信息
Returns **Object** 图层参数信息
### getzIndex
获取图层层级
Returns **Number** zIndex 图层层级
### setzIndex
设置图层层级,数字越大图层层级越高
#### Parameters
- `zIndex` **Number** 图层层级值
### getOpacity
获取图层透明度
Returns **Number** opacity 图层透明度
### setOpacity
设置图层透明度,范围 [0 ~ 1]
#### Parameters
- `opacity` **Number** 图层透明度
### getZooms
获取该图层可显示的级别范围,默认取值范围为[2-30]
Returns **\[Number, Number]** 缩放范围
### setZooms
获取该图层可显示的级别范围
#### Parameters
- `zooms` **\[Number, Number]** 缩放范围
### show
设置图层可见
### hide
设置图层隐藏
### destroy
销毁图层
## Satellite
**Extends TileLayer**
卫星图层类,继承自 TileLayer。
[相关示例][41]
### Parameters
- `opts` **SatelliteLayerOptions**
- `opts.zooms` **\[Number, Number]** 支持的缩放级别范围,默认范围 [2-30] (optional, default `[2,30]`)
- `opts.opacity` **Number** 透明度,默认 1 (optional, default `1`)
- `opts.visible` **Boolean** 是否显示,默认 true (optional, default `true`)
- `opts.zIndex` **Number** 图层叠加的顺序值,1 表示最底层。默认 zIndex:4 (optional, default `4`)
- `opts.tileSize` **Number** 切片大小,取值: </br>
256,表示切片大小为256_256, </br>
128,表示切片大小为128_128, </br>
64,表示切片大小为64\*64。默认值为256 (optional, default `256`)
### getOptions
获取图层参数信息
Returns **Object** 图层参数信息
### getzIndex
获取图层层级
Returns **Number** zIndex 图层层级
### setzIndex
设置图层层级,数字越大图层层级越高
#### Parameters
- `zIndex` **Number** 图层层级值
### getOpacity
获取图层透明度
Returns **Number** opacity 图层透明度
### setOpacity
设置图层透明度,范围 [0 ~ 1]
#### Parameters
- `opacity` **Number** 图层透明度
### getZooms
获取该图层可显示的级别范围,默认取值范围为[2-30]
Returns **\[Number, Number]** 缩放范围
### setZooms
获取该图层可显示的级别范围
#### Parameters
- `zooms` **\[Number, Number]** 缩放范围
### show
设置图层可见
### hide
设置图层隐藏
### destroy
销毁图层
## RoadNet
**Extends TileLayer**
路网图层,展示道路信息 </br>
[相关示例][42]
### Parameters
- `opts` **RoadnetLayerOptions**
- `opts.zooms` **\[Number, Number]** 支持的缩放级别范围,默认范围 [2-30] (optional, default `[2,30]`)
- `opts.opacity` **Number** 透明度,默认 1 (optional, default `1`)
- `opts.visible` **Boolean** 是否显示,默认 true (optional, default `true`)
- `opts.zIndex` **Number** 图层叠加的顺序值,1 表示最底层。默认 zIndex:4 (optional, default `4`)
- `opts.tileSize` **Number** 切片大小,取值: </br>
256,表示切片大小为256_256, </br>
128,表示切片大小为128_128, </br>
64,表示切片大小为64\*64。默认值为256 (optional, default `256`)
### show
设置图层可见
### hide
设置图层隐藏
### getOptions
获取图层参数信息
Returns **Object** 图层参数信息
### getzIndex
获取图层层级
Returns **Number** zIndex 图层层级
### setzIndex
设置图层层级,数字越大图层层级越高
#### Parameters
- `zIndex` **Number** 图层层级值
### getOpacity
获取图层透明度
Returns **Number** opacity 图层透明度
### setOpacity
设置图层透明度,范围 [0 ~ 1]
#### Parameters
- `opacity` **Number** 图层透明度
### getZooms
获取该图层可显示的级别范围,默认取值范围为[2-30]
Returns **\[Number, Number]** 缩放范围
### setZooms
获取该图层可显示的级别范围
#### Parameters
- `zooms` **\[Number, Number]** 缩放范围
### destroy
销毁图层
## Buildings
**Extends Layer**
建筑楼块 3D 图层 </br>
[相关示例][43]
### Parameters
- `opts` **BuildingLayerOpts**
- `opts.wallColor` **(Array<String> | String)** 楼块侧面颜色,支持 rgba、rgb、十六进制等
- `opts.roofColor` **(Array<String> | String)** 楼块顶面颜色,支持 rgba、rgb、十六进制等
- `opts.heightFactor` **Number** 楼块的高度系数因子,默认为 1,也就是正常高度
- `opts.styleOpts` **BuildingStyleOptions** 楼块的围栏和样式设置
- `opts.zooms` **\[Number, Number]** 图层缩放等级范围,默认 [2, 20] (optional, default `[2,20]`)
- `opts.opacity` **Number** 图层透明度,默认为 1 (optional, default `1`)
- `opts.visible` **Boolean** 图层是否可见,默认为 true (optional, default `true`)
- `opts.zIndex` **Number** 图层的层级,默认为 11 (optional, default `11`)
### Examples
```javascript
var buildingLayer = new AMap.Buildings({
heightFactor: 1,
wallColor: [255, 0, 0, 1],
roofColor: 'rgba(0,0,255,0.5)',
});
map.addLayer(buildingLayer);
```
### setStyle
设置楼块图层样式 </br>
[相关示例][43]
#### Parameters
- `styleOpts` **BuildingStyleOptions** 样式
- `styleOpts.hideWithoutStyle` **Boolean** 是否隐藏围栏之外的楼块
- `styleOpts.areas` **Array<Area>** 围栏信息数组
- `styleOpts.areas.rejectTexture` **Boolean** 是否隐藏围栏之外的楼块
- `styleOpts.areas.visible` **Boolean** 围栏信息数组
- `styleOpts.areas.path` **Array<Number>** 围栏经纬度列表
- `styleOpts.areas.color1` **(Array<String> | String)** 围栏区域内楼块顶面颜色,支持 rgba、rgb、十六进制等
- `styleOpts.areas.color2` **(Array<String> | String)** 围栏区域内楼块侧面颜色,支持 rgba、rgb、十六进制等
#### Examples
```javascript
var options = {
hideWithoutStyle:false,//是否隐藏设定区域外的楼块
areas:[{ //围栏1
//visible:false,//是否可见
rejectTexture:true,//是否屏蔽自定义地图的纹理
color1: 'ffffff00',//楼顶颜色
color2: 'ffffcc00',//楼面颜色
path: [[116.473606,39.995997],[116.473005,39.995482],[116.474179,39.996516],[116.473606,39.995997]]
}, { //围栏2
color1: 'ff99ff00',
color2: 'ff999900',
path: [[116.474609,39.993478],[116.474489,39.993495],[116.47469,39.99348],[116.474609,39.993478]]
}]
};
buildingLayer.setStyle(options); //此配色优先级高于自定义mapStyle
```
### getOptions
获取图层参数信息
Returns **object** 图层参数信息
### getzIndex
获取图层层级
Returns **Number** zIndex 图层层级
### setzIndex
设置图层层级,数字越大图层层级越高
#### Parameters
- `zIndex` **Number** 图层层级值
### getOpacity
获取图层透明度
Returns **Number** opacity 图层透明度
### setOpacity
设置图层透明度,范围 [0 ~ 1]
#### Parameters
- `opacity` **Number** 图层透明度
### getZooms
获取该图层可显示的级别范围,默认取值范围为[2-20]
Returns **\[Number, Number]** 缩放范围
### setZooms
获取该图层可显示的级别范围
#### Parameters
- `zooms` **\[Number, Number]** 缩放范围
### show
设置图层可见
### hide
设置图层隐藏
### destroy
销毁图层
## DistrictLayer
**Extends \_Layer.CoreDistrictLayer**
### Parameters
- `opts`
### setSOC
设定显示的国家 SOC
#### Parameters
- `SOC` **String** SOC
### setDistricts
设置 adcodes 值
#### Parameters
- `adcodes` **(Array<any> | string \| number)** adcodes
### getDistricts
获取 adcodes
Returns **any** adcodes
### setStyles
设置样式信息
#### Parameters
- `styles` **DistrictLayerStyle** 样式信息
### getStyles
获取样式信息
Returns **DistrictLayerStyle** 样式
### setAdcode
设置 adcodes 值
#### Parameters
- `adcodes` **(Array<any> | string \| number)** adcodes
### getOptions
获取图层参数信息
Returns **object** 图层参数信息
### getzIndex
获取图层层级
Returns **Number** zIndex 图层层级
### setzIndex
设置图层层级,数字越大图层层级越高
#### Parameters
- `zIndex` **Number** 图层层级值
### getOpacity
获取图层透明度
Returns **Number** opacity 图层透明度
### setOpacity
设置图层透明度,范围 [0 ~ 1]
#### Parameters
- `opacity` **Number** 图层透明度
### getZooms
获取该图层可显示的级别范围,默认取值范围为[2-20]
Returns **\[number, number]** 缩放范围
### setZooms
获取该图层可显示的级别范围
#### Parameters
- `zooms` **\[number, number]** 缩放范围
### show
设置图层可见
### hide
设置图层隐藏
### World
世界级行政区
[相关示例][46]
### Country
国家级行政区
[相关示例][47]
### Province
省份级行政区,只支持中国区域
[相关示例][48]
## DistrictLayer
**Extends Layer**
### Parameters
- `opts` **DistrictLayerOptions** 图层初始化参数
- `opts.adcode` **String** 行政区的编码 [adcode与省市行政区对照表][49]
- `opts.SOC` **String** 设定显示的国家
[SOC 国家代码、名称、Bounds对照表下载][50] (optional, default `'CHN'`)
- `opts.depth` **Number** 设定数据的层级深度,depth为0的时候只显示国家面,depth为1的时候显示省级,
当国家为中国时设置depth为2的可以显示市一级 (optional, default `0`)
- `opts.zIndex` **Number** 图层的层级,默认为 80 (optional, default `80`)
- `opts.opacity` **Number** 图层透明度,默认为 1 (optional, default `1`)
- `opts.visible` **Boolean** 图层是否可见,默认为 true (optional, default `true`)
- `opts.zooms` **\[number, number]** 图层缩放等级范围,默认 [2, 20] (optional, default `[2,20]`)
- `opts.styles` **DistrictLayerStyle** 为简易行政区图设定各面的填充颜色和描边颜色。
styles各字段的值可以是颜色值,也可以是一个返回颜色值\* 的回调函数function。支持的颜色格式有: </br>
1\. #RRGGBB,如:'#FFFFFF' </br>
2\. rgba(),如:'rgba(255,255,255,1)' </br>
3\. rgb(),如:'rgb(255,255,255)' </br>
4\. [r,g,b,a],如:[1,1,1,1] </br>
5\. '',代表不赋予颜色
- `opts.styles.stroke-width` **(Number \| Function)** 描边线宽 (optional, default `1`)
- `opts.styles.zIndex` **(Number \| Function)** 图层中每个区域层级,数值越大,层级越高 (optional, default `0`)
- `opts.styles.coastline-stroke` **(Array<String> | String \| Function)** 海岸线颜色 (optional, default `[0.18,0.63,0.94,1]`)
- `opts.styles.nation-stroke` **(Array<String> | String \| Function)** 国境线颜色 (optional, default `[0.35,0.35,0.35,1]`)
- `opts.styles.province-stroke` **(Array<String> | String \| Function)** 省界颜色 (optional, default `[0.5,0.5,0.5,1]`)
- `opts.styles.city-stroke` **(Array<String> | String \| Function)** 城市界颜色 (optional, default `[0.7,0.7,0.7,1]`)
- `opts.styles.county-stroke` **(Array<String> | String \| Function)** 区/县界颜色 (optional, default `[0.85,0.85,0.85,1]`)
- `opts.styles.fill` **(Array<String> | String \| Function)** 填充色 (optional, default `[1,1,1,1]`)
### setSOC
设定显示的国家 SOC
#### Parameters
- `SOC` **String** SOC
### setDistricts
设置 adcodes 值
#### Parameters
- `adcodes` **(Array<any> | string \| number)** adcodes
### getDistricts
获取 adcodes
Returns **any** adcodes
### setStyles
设置样式信息
#### Parameters
- `styles` **DistrictLayerStyle** 样式信息
### getStyles
获取样式信息
Returns **DistrictLayerStyle** 样式
### setAdcode
设置 adcodes 值
#### Parameters
- `adcodes` **(Array<any> | string \| number)** adcodes
### getOptions
获取图层参数信息
Returns **object** 图层参数信息
### getzIndex
获取图层层级
Returns **Number** zIndex 图层层级
### setzIndex
设置图层层级,数字越大图层层级越高
#### Parameters
- `zIndex` **Number** 图层层级值
### getOpacity
获取图层透明度
Returns **Number** opacity 图层透明度
### setOpacity
设置图层透明度,范围 [0 ~ 1]
#### Parameters
- `opacity` **Number** 图层透明度
### getZooms
获取该图层可显示的级别范围,默认取值范围为[2-20]
Returns **\[number, number]** 缩放范围
### setZooms
获取该图层可显示的级别范围
#### Parameters
- `zooms` **\[number, number]** 缩放范围
### show
设置图层可见
### hide
设置图层隐藏
### World
世界级行政区
[相关示例][46]
### Country
国家级行政区
[相关示例][47]
### Province
省份级行政区,只支持中国区域
[相关示例][48]
## IndoorMap
**Extends \_layer.IndoorLayer**
### Parameters
- `opts`
### showIndoorMap
显示指定 POI 的室内地图
#### Parameters
- `indoorid` **String** 建筑物 POIID (必填) [如何获取][51]
- `floor` **Number** 楼层
- `shopid` **String** 商铺 ID
### showFloor
显示指定的楼层
#### Parameters
- `floor` **number** 楼层
### show
显示室内地图
### hide
隐藏室内地图
### setMap
设置显示室内图层的地图对象
#### Parameters
- `map` **Map**
### setzIndex
设置室内地图的显示顺序
#### Parameters
- `index` **number**
### showFloorBar
显示楼层切换控件
### hideFloorBar
隐藏楼层切换控件
### setOpacity
设置室内图层透明度
#### Parameters
- `opacity` **number**
### getOpacity
获取室内图层透明度
Returns **number**
### showLabels
显示室内图层上的标注
### hideLabels
隐藏室内图层上的标注
### getSelectedBuildingId
获取被选中室内的 POIID
### getSelectedBuilding
获取被选中的室内地图的一些基本信息,包含名称、当前楼层、所有楼层信息、POIID等
## IndoorMap
室内图层,用于在适当级别展示室内地图,并提供显示商铺tip、切换楼层等功能。
### Parameters
- `opts` **IndoorMapOptions**
- `opts.zIndex` **Number** 室内图层叠加的顺序值
- `opts.opacity` **Number** 图层的透明度,取值范围[0,1]
- `opts.cursor` **String** 指定鼠标悬停到店铺面时的鼠标样式
- `opts.hideFloorBar` **Boolean** 是否隐藏楼层切换控件,默认值:false
### Examples
```javascript
用法一:创建独立的室内图层
var indoorMap = new AMap.IndoorMap({
zIndex: 1000, // 设置室内图层叠加顺序
opacity: 1, // 设置室内图层透明度
});
var map = new AMap.Map('mapDiv', {
showIndoorMap: false, //隐藏地图默认的室内地图图层
layers: [indoorMap, AMap.createDefaultLayer()] // 添加室内等图层
});
indoorMap.showIndoorMap('B0FFFAB6J2'); // 显示指定 POI 室内信息
用法二:调用默认室内图层
var map = new AMap.Map('mapDiv',{
showIndoorMap: true, //显示地图默认的室内地图图层
});
map.on('indoor_create',function(){
map.indoorMap.showIndoorMap('B000A8VT15',4); // 显示指定 POI 室内信息
})
```
### showIndoorMap
显示指定 POI 的室内地图
#### Parameters
- `indoorid` **String** 建筑物 POIID (必填) [如何获取][51]
- `floor` **Number** 楼层
- `shopid` **String** 商铺 ID
### showFloor
显示指定的楼层
#### Parameters
- `floor` **number** 楼层
### show
显示室内地图
### hide
隐藏室内地图
### setMap
设置显示室内图层的地图对象
#### Parameters
- `map` **Map**
### setzIndex
设置室内地图的显示顺序
#### Parameters
- `index` **number**
### showFloorBar
显示楼层切换控件
### hideFloorBar
隐藏楼层切换控件
### setOpacity
设置室内图层透明度
#### Parameters
- `opacity` **number**
### getOpacity
获取室内图层透明度
Returns **number**
### showLabels
显示室内图层上的标注
### hideLabels
隐藏室内图层上的标注
### getSelectedBuildingId
获取被选中室内的 POIID
### getSelectedBuilding
获取被选中的室内地图的一些基本信息,包含名称、当前楼层、所有楼层信息、POIID等
FILE:references/api/layers-standard.md
## 行业标准图层
符合 OGC 标准或者行业通行规范的的图层类型
## WMS
**Extends TileLayer**
用于加载OGC标准的WMS地图服务的一种图层类,仅支持EPSG3857坐标系统的WMS图层。 </br>
[查看 WMS的OGC标准][53]。
### Parameters
- `opts` **WMSLayerOptions** 默认图层参数
- `opts.url` **String** wmts服务的url地址,如:'[https://services.arcgisonline.com/arcgis/rest/services/'+][54]
'Demographics/USA_Population_Density/MapServer/WMTS/'
- `opts.blend` **Boolean** 地图级别切换时,不同级别的图片是否进行混合,如图层的图像内容为部分透明请设置为false
- `opts.param` **Object** OGC标准的WMS地图服务的GetMap接口的参数,包括VERSION、LAYERS、STYLES、FORMAT、TRANSPARENT等, </br>
CRS、BBOX、REQUEST、WIDTH、HEIGHT等参数请勿添加,例如: </br>
{ </br>
LAYERS: 'topp:states', </br>
VERSION:'1.3.0', </br>
FORMAT:'image/png' </br>
}
- `opts.zooms` **\[Number, Number]** 支持的缩放级别范围,默认范围 [2-30] (optional, default `[2,30]`)
- `opts.opacity` **Number** 透明度,默认 1 (optional, default `1`)
- `opts.visible` **Boolean** 是否显示,默认 true (optional, default `true`)
- `opts.zIndex` **Number** 图层叠加的顺序值,1 表示最底层。默认 zIndex:4 (optional, default `4`)
### setParams
设置OGC标准的WMS getMap接口的参数,包括VERSION、LAYERS、STYLES、FORMAT、TRANSPARENT等
#### Parameters
- `params` **Object** 参数集合,{VERSION: '1.0', ...}
### getParams
获取 OGC 标准的 WMS getMap 接口的参数
### setUrl
设置 WMS 服务地址
#### Parameters
- `url` **String** 服务地址
### setUrl
设置 WMS 服务地址
#### Parameters
- `url` **String** 服务地址
### getOptions
获取图层参数信息
Returns **Object** 图层参数信息
### getzIndex
获取图层层级
Returns **Number** zIndex 图层层级
### setzIndex
设置图层层级,数字越大图层层级越高
#### Parameters
- `zIndex` **Number** 图层层级值
### getOpacity
获取图层透明度
Returns **Number** opacity 图层透明度
### setOpacity
设置图层透明度,范围 [0 ~ 1]
#### Parameters
- `opacity` **Number** 图层透明度
### getZooms
获取该图层可显示的级别范围,默认取值范围为[2-30]
Returns **\[Number, Number]** 缩放范围
### setZooms
获取该图层可显示的级别范围
#### Parameters
- `zooms` **\[Number, Number]** 缩放范围
### show
设置图层可见
### hide
设置图层隐藏
## WMTS
**Extends TileLayer**
用于加载 OGC 标准的 WMTS 地图服务的一种图层类,仅支持 EPSG3857 坐标系统的 WMTS 图层 </br>
[查看 WMTS 标准][55] </br>
[相关示例][56]
### Parameters
- `opts` **WMTSLayerOptions** 默认图层参数
- `opts.url` **String** wms服务的url地址,如'[https://ahocevar.com/geoserver/wms][57]'
- `opts.blend` **Boolean** 地图级别切换时,不同级别的图片是否进行混合,如图层的图像内容为部分透明请设置为false
- `opts.param` **Object** OGC标准的WMTS地图服务的GetTile接口的参数,包括Version、Layer、
Style、Format、Service等,TileMatrixSet、TileRow、TileCol、Request等参数请勿添加,例如: </br>
{ </br>
Layer: '0', </br>
Version:'1.0.0', </br>
Format: 'image/png' </br>
}
- `opts.zooms` **\[Number, Number]** 支持的缩放级别范围,默认范围 [2-30] (optional, default `[2,30]`)
- `opts.opacity` **Number** 透明度,默认 1 (optional, default `1`)
- `opts.visible` **Boolean** 是否显示,默认 true (optional, default `true`)
- `opts.zIndex` **Number** 图层叠加的顺序值,1 表示最底层。默认 zIndex:4 (optional, default `4`)
### setParams
设置 OGC 标准的 WMTS getTile接口的参数,包括Version、Layer、Style、Format、Service等
#### Parameters
- `params` **Object** 参数集合,{VERSION: '1.0', ...}
### getParams
获取 OGC 标准的 WMTS getMap 接口的参数
### getUrl
获取 WMTS 服务地址
Returns **String** 地址
### setUrl
设置 WMTS 服务地址
#### Parameters
- `url` **String** 服务地址
### getOptions
获取图层参数信息
Returns **Object** 图层参数信息
### getzIndex
获取图层层级
Returns **Number** zIndex 图层层级
### setzIndex
设置图层层级,数字越大图层层级越高
#### Parameters
- `zIndex` **Number** 图层层级值
### getOpacity
获取图层透明度
Returns **Number** opacity 图层透明度
### setOpacity
设置图层透明度,范围 [0 ~ 1]
#### Parameters
- `opacity` **Number** 图层透明度
### getZooms
获取该图层可显示的级别范围,默认取值范围为[2-30]
Returns **\[Number, Number]** 缩放范围
### setZooms
获取该图层可显示的级别范围
#### Parameters
- `zooms` **\[Number, Number]** 缩放范围
### show
设置图层可见
### hide
设置图层隐藏
## MapboxVectorTileLayer
**Extends Layer**
为了满足基于矢量瓦片块的数据可视化、矢量瓦片边界展示等开发需求,通过 AMap.MapboxVectorTileLayer 插件提供了简易矢量瓦片图层</br>
此图层可以使用标准的 MVT 瓦片服务作为数据源。</br>
可以配合[GeoHub-数据中心][58]发布的矢量瓦片服务。
注意:使用高德数据平台发布服务,由于服务 URL 地址是明文,建议自行做服务代理转发,防止服务 ID 和 Key 明文传输导致数据泄露。</br>
[相关示例][59]
### Parameters
- `opts` **MapboxVTLayerOptions** 图层初始化参数
- `opts.zIndex` **Number** 图层的层级 (optional, default `80`)
- `opts.opacity` **Number** 图层透明度 (optional, default `1`)
- `opts.url` **String?** MVT 数据的链接地址
- `opts.visible` **Boolean** 图层是否可见 (optional, default `true`)
- `opts.zooms` **\[number, number]** 图层缩放等级范围 (optional, default `[2,22]`)
- `opts.dataZooms` **\[number, number]** 瓦片数据等级范围,超过范围会使用最大/最小等级的数据 (optional, default `[2,18]`)
- `opts.styles` **MapboxVTLayerStyle**
- `opts.styles.polygon` **PolygonStyle?** 面类型的样式
- `opts.styles.polygon.sourceLayer` **String** 使用数据中的哪个图层,默认使用 default 图层 (optional, default `'default'`)
- `opts.styles.polygon.color` **(String \| Function)?** 面填充颜色
- `opts.styles.polygon.borderWidth` **(Number \| Function)?** 描边宽度
- `opts.styles.polygon.dash` **(Array<Number> | Function)?** 描边线的虚线配置,例如:[10,5,8,5]
- `opts.styles.polygon.borderColor` **(String \| Function)?** 描边颜色
- `opts.styles.polygon.injection` **Array<Any>?** 其他属性值中对于函数形式的值,假如需要获取外部变量,要使用数组的形式传入,便于在函数内部访问外部变量。请看下面的示例。
- `opts.styles.polygon.visible` **(Boolean \| Function)?** 是否显示
- `opts.styles.line` **LineStyle?** 线类型数据的样式
- `opts.styles.line.sourceLayer` **String** 使用数据中的哪个图层,默认使用 default 图层 (optional, default `'default'`)
- `opts.styles.line.color` **(String \| Function)?** 线填充颜色
- `opts.styles.line.lineWidth` **(Number \| Function)?** 宽度
- `opts.styles.line.dash` **(String \| Function)?** 虚线配置,例如:[10,5,8,5]
- `opts.styles.line.injection` **Array<Any>?** 其他属性值中对于函数形式的值,假如需要获取外部变量,要使用数组的形式传入,便于在函数内部访问外部变量。请看下面的示例。
- `opts.styles.line.visible` **(Boolean \| Function)?** 是否显示
- `opts.styles.point` **PointStyle?** 点类型数据的样式
- `opts.styles.point.sourceLayer` **String** 使用数据中的哪个图层,默认使用 default 图层 (optional, default `'default'`)
- `opts.styles.point.radius` **(String \| Function)?** 圆点的半径,单位像素
- `opts.styles.point.color` **(Number \| Function)?** 圆的填充颜色
- `opts.styles.point.borderWidth` **(String \| Function)?** 描边的宽度
- `opts.styles.point.borderColor` **(String \| Function)?** 描边的颜色
- `opts.styles.point.injection` **Array<Any>?** 其他属性值中对于函数形式的值,假如需要获取外部变量,要使用数组的形式传入,便于在函数内部访问外部变量。请看下面的示例。
- `opts.styles.point.visible` **(Boolean \| Function)?** 是否显示
- `opts.styles.polyhedron` **PolyhedronStyle?** 多面体类型的样式
- `opts.styles.polyhedron.sourceLayer` **String** 使用数据中的哪个图层,默认使用 default 图层 (optional, default `'default'`)
- `opts.styles.polyhedron.topColor` **(String \| Function)?** 顶面颜色
- `opts.styles.polyhedron.sideColor` **(String \| Function)?** 侧面颜色
- `opts.styles.polyhedron.texture` **(String \| Function)?** 侧面纹理,优先级高于侧面颜色
- `opts.styles.polyhedron.injection` **Array<Any>?** 其他属性值中对于函数形式的值,假如需要获取外部变量,要使用数组的形式传入,便于在函数内部访问外部变量。请看下面的示例。
- `opts.styles.polyhedron.visible` **(Boolean \| Function)?** 是否显示
### Examples
```javascript
var globalVar = ['这是', '一个', '外部', '变量'];
var mvtl = new AMap.MapboxVectorTileLayer({
zIndex: 150,
opacity: 1,
// URL可以使用数据服务平台的服务,也可以使用自己发布的 MVT 数据服务
url: 'https://restapi.amap.com/rest/lbs/geohub/tiles/mvt?z=[z]&x=[x]&y=[y]&size=512&key=您申请的key值&id=数据服务ID',
dataZooms: [2, 18],
zooms: [2, 20],
tileSize: 256,
styles: {
point: {
sourceLayer: 'default',
visible: function (f, inject) {
// 这里的 inject 参数就是一个数组,他的值就是 injection 字段的数组值:[visis]。
return inject[0].indexOf('这是') > -1;
},
injection: [globalVar],
radius: function (props) {
return Math.random() * 20 + 5;
},
color: 'red',
borderWidth: 20 || function (props) {
return Math.random() * 5 + 2;
},
borderColor: 'rgba(255,255,255,1)',
},
polygon: {
sourceLayer: 'default',
color: function (props) {
return 'rgba(0,0,0,1)';
},
dash: [10, 0, 10, 0],
borderColor: 'rgba(30,112,255,1)',
borderWidth: 5,
},
line: {
sourceLayer: 'default',
color: 'rgba(20,140,40,1)',
lineWidth: 5,
dash: [10, 0, 10, 0],
},
polyhedron: {
sourceLayer: 'default',
topColor: 'rgba(230,230,230,0.9)',
sideColor: 'rgba(240,240,240,0.9)',
},
}
});
```
### setStyles
设置样式信息
#### Parameters
- `styles` **MapboxVTLayerStyle** 样式信息
### filterByRect
获取矩形范围的要素
#### Parameters
- `rect` **Polygon** 多边型,例如:\[[lng,lat],[lng,lat],[lng,lat],[lng,lat],[lng,lat]]
- `type` **String** 想要获取的要素类型,默认选择所有:all。可选值:all、point、polygon、line (optional, default `"all"`)
Returns **Array<Feature>**
### getStyles
获取样式信息
Returns **MapboxVTLayerStyle** 样式
### on
图层级别监听鼠标事件
获取当前图层中鼠标位置的要素
#### Parameters
- `type` **String** 监听事件类型,目前支持 click、mousemove
- `fn` **Function** 监听的回调函数,参数中的 features 是获取的鼠标位置的要素
- `option` **Object** 拾取参数,featType:代表需要拾取的要素类型,参考 filterByRect() 函数中的 type;buffer:5, 代表以鼠标为中心点,范围为 5 的方形区域为鼠标拾取范围。值越大,拾取的范围越大,建议使用默认值。
### hide
设置图层隐藏
### hide
设置图层隐藏
### getOptions
获取图层参数信息
Returns **object** 图层参数信息
### getzIndex
获取图层层级
Returns **Number** zIndex 图层层级
### setzIndex
设置图层层级,数字越大图层层级越高
#### Parameters
- `zIndex` **Number** 图层层级值
### getOpacity
获取图层透明度
Returns **Number** opacity 图层透明度
### setOpacity
设置图层透明度,范围 [0 ~ 1]
#### Parameters
- `opacity` **Number** 图层透明度
### getZooms
获取该图层可显示的级别范围,默认取值范围为[2-20]
Returns **\[number, number]** 缩放范围
### setZooms
获取该图层可显示的级别范围
#### Parameters
- `zooms` **\[number, number]** 缩放范围
### show
设置图层可见
FILE:references/api/map.md
## 地图
## Map
地图对象类,封装了地图的属性设置、图层变更、事件交互等接口的类。</br>
[相关示例][10]
### Parameters
- `div` **(String \| HTMLDivElement)** 构造一个地图对象,参数container中传入地图容器DIV的ID值或者DIV对象,
opts地图初始化参数对象,参数详情参看MapOptions列表。注意:地图容器在创建之前必须拥有实际大小,否则可能出现底图无法渲染的问题。
- `opts` **MapOptions** 地图初始化参数
- `opts.center` **(\[Number, Number] | LngLat)** 初始中心经纬度
- `opts.zoom` **Number** 地图显示的缩放级别,可以设置为浮点数;若center与level未赋值,地图初始化默认显示用户所在城市范围。
- `opts.rotation` **Number** 地图顺时针旋转角度,取值范围 [0-360],默认值:0 (optional, default `0`)
- `opts.pitch` **Number** 俯仰角度,默认 0,最大值根据地图当前 zoom 级别不断增大,2D地图下无效 。 (optional, default `0`)
- `opts.viewMode` **String** 地图视图模式, 默认为‘2D’,可选’3D’,选择‘3D’会显示 3D 地图效果。 (optional, default `'2D'`)
- `opts.features` **Array<String>** 设置地图上显示的元素种类, 支持'bg'(地图背景)、'point'(POI点)、'road'(道路)、'building'(建筑物) (optional, default `['bg','point','road','building']`)
- `opts.layers` **Array<Layer>** 地图图层数组,数组可以是图层 中的一个或多个,默认为普通二维地图。
当叠加多个[图层][15]时,普通二维地图需通过实例化一个TileLayer类实现。
如果你希望创建一个默认底图图层,使用 AMap.createDefaultLayer()
- `opts.zooms` **\[Number, Number]** 地图显示的缩放级别范围, 默认为[2, 20],取值范围[2 ~ 30] (optional, default `[2,20]`)
- `opts.dragEnable` **Boolean** 地图是否可通过鼠标拖拽平移, 默认为 true。此属性可被 setStatus/getStatus 方法控制 (optional, default `true`)
- `opts.zoomEnable` **Boolean** 地图是否可缩放,默认值为 true。此属性可被 setStatus/getStatus 方法控制 (optional, default `true`)
- `opts.jogEnable` **Boolean** 地图是否使用缓动效果,默认值为true。此属性可被setStatus/getStatus 方法控制 (optional, default `true`)
- `opts.pitchEnable` **Boolean** 是否允许设置俯仰角度, 3D 视图下为 true, 2D 视图下无效。 (optional, default `true`)
- `opts.rotateEnable` **Boolean** 地图是否可旋转, 图默认为true (optional, default `true`)
- `opts.animateEnable` **Boolean** 地图平移过程中是否使用动画(如调用panBy、panTo、setCenter、setZoomAndCenter等函数,
将对地图产生平移操作, 是否使用动画平移的效果), 默认为true, 即使用动画 (optional, default `true`)
- `opts.keyboardEnable` **Boolean** 地图是否可通过键盘控制, 默认为true, 方向键控制地图平移,"+"和"-"可以控制地图的缩放,
Ctrl+“→”顺时针旋转,Ctrl+“←”逆时针旋转。此属性可被setStatus/getStatus 方法控制 (optional, default `true`)
- `opts.doubleClickZoom` **Boolean** 地图是否可通过双击鼠标放大地图, 默认为true。此属性可被setStatus/getStatus 方法控制 (optional, default `true`)
- `opts.scrollWheel` **Boolean** 地图是否可通过鼠标滚轮缩放浏览,默认为true。此属性可被setStatus/getStatus 方法控制 (optional, default `true`)
- `opts.touchZoom` **Boolean** 地图在移动终端上是否可通过多点触控缩放浏览地图,默认为true。关闭手势缩放地图,请设置为false。 (optional, default `true`)
- `opts.touchZoomCenter` **Boolean** 可缺省,当touchZoomCenter=1的时候,手机端双指缩放的以地图中心为中心,否则默认以双指中间点为中心。 (optional, default `1`)
- `opts.showLabel` **Boolean** 是否展示地图文字和 POI 信息。 (optional, default `true`)
- `opts.defaultCursor` **String** 地图默认鼠标样式。参数 defaultCursor 应符合 CSS 的 cursor 属性规范。
- `opts.isHotspot` **Boolean** 是否开启地图热点和标注的 hover 效果。PC端默认是true, 移动端默认是 false。
- `opts.mapStyle` **String** 设置地图的显示样式,目前支持两种地图样式:
第一种:自定义地图样式,如 "amap://styles/d6bf8c1d69cea9f5c696185ad4ac4c86"
可前往地图自定义平台定制自己的个性地图样式;
第二种:官方样式模版,如"amap://styles/grey"。
其他模版样式及自定义地图的使用说明见开发指南
- `opts.wallColor` **(String \| Array<Number>)** 地图楼块的侧面颜色
- `opts.roofColor` **(String \| Array<Number>)** 地图楼块的顶面颜色
- `opts.showBuildingBlock` **Boolean** 是否展示地图 3D 楼块,默认 true (optional, default `true`)
- `opts.showIndoorMap` **Boolean** 是否自动展示室内地图,默认是 false (optional, default `false`)
- `opts.skyColor` **(String \| Array<Number>)** 天空颜色,3D 模式下带有俯仰角时会显示
- `opts.labelRejectMask` **Boolean** 文字是否拒绝掩模图层进行掩模 (optional, default `false`)
- `opts.mask` **Array<Number>** 为 Map 实例指定掩模的路径,各图层将只显示路径范围内图像,3D视图下有效。
格式为一个经纬度的一维、二维或三维数组。 </br> [相关示例][16] </br>
一维数组时代表一个普通多边形路径,如: </br>
[lng1,lat1], [lng2,lat2], [lng3,lat3]]
二维数组时代表一个带洞的多边形路径,如: </br>
\[[lng4,lat4], [lng5,lat5], [lng6,lat6]],
\[[lng7,lat7], [lng8,lat8], [lng9,lat9]]
]
三维数组时代表多个多边形路径,如: </br>
\[
\[[lng1,lat1], [lng2,lat2], [lng3,lat3]], // 一个普通多边形
\[ //一个带洞多边形
\[[lng4,lat4], [lng5,lat5], [lng6,lat6]],
\[[lng7,lat7], [lng8,lat8], [lng9,lat9]]
]
]
- `opts.WebGLParams` **any** 额外配置的WebGL参数 eg: preserveDrawingBuffer (optional, default `{}`)
### Examples
```javascript
var map = new AMap.Map('map', {
viewMode: '3D',
center: [116.397083, 39.874531],
layers: [AMap.createDefaultLayer()], // layers 字段为空或者不赋值将会自动创建默认底图。
zoom: 12,
})
```
### resize
重新计算容器大小
### setCenter
设置中心点 </br>
[相关示例][17]
#### Parameters
- `center` **(\[number, number] | LngLat)** 中心点经纬度
- `immediately` **Boolean** 是否立即过渡到目标位置 (optional, default `false`)
- `duration` **Number?** 如果使用动画过度,动画过度的时长控制,单位 ms,默认值是内部自动计算的一个动态值。
### setZoomAndCenter
地图缩放至指定级别并以指定点为地图显示中心点 </br>
[相关示例][18]
#### Parameters
- `zoom` **Number** 缩放等级
- `center` **(LngLat | \[number, number])** 地图中心点位置
- `immediately` **Boolean** 是否立即过渡到目位置 (optional, default `false`)
- `duration` **Number?** 如果使用动画过度,动画过度的时长控制,单位 ms,默认值是内部自动计算的一个动态值。
### getBounds
获取当前地图视图范围/可视区域。 </br>
[相关示例][19]
Returns **Bounds** 边界经纬度
### getCenter
获取地图中心点经纬度坐标值。 </br>
[相关示例][21]
Returns **LngLat** 地图中心点经纬度
### setZoom
设置地图显示的缩放级别,参数 zoom 可设范围:[2, 30]
#### Parameters
- `zoom` **Number** 地图缩放等级
- `immediately` **Boolean** 是否立即过渡到目标位置 (optional, default `false`)
- `duration` **Number?** 如果使用动画过度,动画过度的时长控制,单位 ms,默认值是内部自动计算的一个动态值。
### getZoom
获取当前地图缩放级别, 默认取值范围为[2, 20]
#### Parameters
- `digits` **Number** zoom级别的小数位精度,缺省为2
Returns **Number** 地图缩放等级
### zoomIn
地图放大一级显示
### zoomOut
地图缩小一级显示
### getPitch
获取地图当前俯仰角
Returns **Number** 角度
### setPitch
设置地图俯仰角
#### Parameters
- `Pitch` **Number** 角度
- `immediately` **Boolean** 是否立即过渡到目标位置 (optional, default `false`)
- `duration` **Number?** 如果使用动画过度,动画过度的时长控制,单位 ms,默认值是内部自动计算的一个动态值。
### getRotation
获取地图顺时针旋转角度, 范围: [0 ~ 360]
Returns **Number** 旋转角度值
### setRotation
设置地图顺时针旋转角度, 旋转原点为地图容器中心点, 取值范围: 任意数字
#### Parameters
- `rotation` **Number** 旋转角度
- `immediately` **Boolean** 是否立即过渡到目标位置 (optional, default `false`)
- `duration` **Number?** 动画过度的时长控制,单位 ms,默认值是内部自动计算的一个动态值。
### setBounds
指定当前地图显示范围,参数 bounds 为指定的范围
#### Parameters
- `bounds` **(Array<number> | Bounds)** 经纬度范围
- `immediately` **boolean** 立即缩放到指定位置 (optional, default `false`)
- `avoid` **Array<number>** 距离边框的内边距,顺序:上、下、左、右 (optional, default `[0,0,0,0]`)
### panTo
地图中心点平移至指定点位置
#### Parameters
- `lnglat` **(\[number, number] | LngLat)**
- `duration` **Number?** 动画过度的时长控制,单位 ms,默认值是内部自动计算的一个动态值。
### getContainer
返回地图对象的容器
Returns **HTMLElement** 地图 DOM 容器
### getSize
获取地图容器尺寸,单位:像素
Returns **Size** 地图容器尺寸
### panBy
以像素为单位, 沿 x 方向和 y 方向移动地图, x 向右为正, y 向下为正
#### Parameters
- `x` **Number** 横轴方向
- `y` **Number** 纵轴方向
- `duration` **Number?** 如果使用动画过度,动画过度的时长控制,单位 ms,默认值是内部自动计算的一个动态值。
### addLayer
添加图层到地图上
#### Parameters
- `layer` **Layer** 地图图层对象
### removeLayer
从地图上移除图层
#### Parameters
- `layer` **Layer** 地图图层
### setLayers
将多个图层一次替代地图上原有图层,会移除地图原有图层
#### Parameters
- `layers` **Array<Layer>** 地图图层数组
### getLayers
获取地图图层数组,数组为一个或多个图层
Returns **Array<Layer>** 地图图层数组
### add
添加覆盖物/图层。参数为单个覆盖物/图层,或覆盖物/图层的数组。
#### Parameters
- `features` **(VectorOverlay | Array<any>)** 覆盖物对象或者数组
### getStatus
获取当前地图状态信息,包括是否可鼠标拖拽移动地图、地图是否可缩放、地图是否可旋转(rotateEnable)、
是否可双击放大地图、是否可以通过键盘控制地图旋转(keyboardEnable)等
Returns **object** 地图状态信息映射集合
### remove
删除覆盖物/图层。参数为单个覆盖物/图层,或覆盖物/图层的数组。
#### Parameters
- `features` **(Overlay | Layer \| Array<(Overlay | Layer)>)** 覆盖物对象或者数组
### setStatus
设置当前地图显示状态,包括是否可鼠标拖拽移动地图、地图是否可缩放、地图是否可旋转(rotateEnable)、
是否可双击放大地图、是否可以通过键盘控制地图旋转(keyboardEnable)等,
[相关示例][24]
#### Parameters
- `status` **object** 地图状态值映射集合
### lngLatToCoords
经纬度转莫卡托坐标(单位:米)
#### Parameters
- `lnglat` **(\[number, number] | LngLat)** 经纬度
Returns **any** 莫卡托坐标(单位:米)
### coordsToLngLat
莫卡托坐标(单位:米)转经纬度
#### Parameters
- `coords` **(\[number, number])** 莫卡托坐标(单位:米)
Returns **any** 经纬度
### lngLatToContainer
地图经纬度坐标转为地图容器像素坐标 </br>
[相关示例][25]
#### Parameters
- `lnglat` **(Array<number> | LngLat)** 经纬度
Returns **Pixel** 容器像素坐标
### getDefaultCursor
获取地图默认鼠标指针样式
Returns **string** 地图鼠标指针样式
### setDefaultCursor
设置地图默认鼠标指针样式
#### Parameters
- `cursor` **string** 设置鼠标指针默认样式,参数cursor应符合CSS的cursor属性规范。可为CSS标注中的光标样式,
如:setCursor(“pointer”)等;或者自定义的光标样式,
如:setCursor("url('[https://lbs.amap.com/webapi/static/Images//0.png'][26]),pointer")
### containerToLngLat
地图容器坐标转换成经纬度 </br>
[相关示例][25]
#### Parameters
- `pixel` **(Array<number> | Pixel)** 容器像素坐标
Returns **LngLat** 转换成功的经纬度
### coordToContainer
莫卡托(单位:米)转成地图容器坐标
#### Parameters
- `coord` **Array<Number>** 莫卡托坐标(单位:米)
Returns **Array<Number>** 容器像素坐标
### destroy
注销地图对象,并清空地图容器
### containerToCoord
地图容器坐标转成莫卡托(单位:米)
#### Parameters
- `pixel` **(Array<Number> | Pixel)** 容器像素坐标
Returns **Array<Number>** 莫卡托坐标(单位:米)
### pixelToLngLat
平面地图像素坐标转换为地图经纬度坐标
#### Parameters
- `pixel` **(Array<number> | Pixel)** 像素坐标
- `zoom` **Number?** 某个地图级别
Returns **LngLat**
### getLimitBounds
获取Map的限制区域
### lngLatToPixel
经纬度坐标转换成平面地图像素坐标
#### Parameters
- `lnglat` **(Array<number> | LngLat)** 经纬度
- `zoom` **Number?** 某个地图级别,默认是地图当前级别
Returns **Pixel** 转换后的平面像素坐标
### setLimitBounds
设置 Map 的限制区域,设定区域限制后,传入参数为限制的 Bounds。地图仅在区域内可拖拽
[相关示例][27]
### clearLimitBounds
清除 Map 的限制区域
### getZooms
获取地图缩放等级范围
Returns **\[number, number]** zooms
### setZooms
设置地图缩放等级范围
#### Parameters
- `zooms` **\[number, number]**
### getResolution
获取指定位置的地图分辨率,单位:米/像素。
参数point有指定值时,返回指定点地图分辨率,point缺省时,默认返回当前地图中心点位置的分辨率
Returns **Number** 分辨率
### getScale
获取当前地图比例尺。表示当前屏幕距离一米代表实际距离多少米
#### Parameters
- `dpi` **Number**
Returns **Number** 比例尺的值
### getCity
获取地图中心点所在区域,回调函数返回对象属性分别对应为{省,市,区/县} </br>
[相关示例][28]
#### Parameters
- `getCityCallBack` **Function** 查询成功的回调函数
- `lnglat` **Array<Number>** 查询的经纬度
### setCity
按照行政区名称或adcode来设置地图显示的中心点。 </br>
行政区名称支持中国、省、市、区/县名称,如遇重名的情况,会按城市编码表顺序返回第一个。adcode请在城市编码表中查询。 </br>
建议不要同时使用center/setCenter()和setCity(),如一起使用程序将以setCity()作为最后结果。 </br>
[相关示例][29]
#### Parameters
- `cityName` **String** 城市名称
### setFitView
根据地图上添加的覆盖物分布情况,自动缩放地图到合适的视野级别,参数均可缺省。</br>
overlayList为覆盖物数组,缺省时为当前地图上添加的所有覆盖物图层,</br>
immediately代表是否需要动画过程,avoid代表上下左右的像素避让宽度,maxZoom代表fitView之后的最大级 </br>
[相关示例][30]
#### Parameters
- `overlays` **Array<Overlay>** 覆盖物
- `immediately` **Boolean** 是否立即过渡 (optional, default `false`)
- `avoid` **Array<Number>** 四周边距,上、下、左、右 (optional, default `[60,60,60,60]`)
- `maxZoom` **Number** 最大 zoom 级别 (optional, default `zooms[1]`)
#### Examples
```javascript
var map = new AMap.Map({
zoom: 10,
});
var marker = new AMap.Marker({
map: map,
position: [112, 30],
icon: "https://webapi.amap.com/images/car.png",
offset: new AMap.Pixel(-26, -13),
});
var marker1 = new AMap.Marker({
map: map,
position: [110, 31],
icon: "https://webapi.amap.com/images/car.png",
offset: new AMap.Pixel(-26, -13),
});
map.setFitView(
[marker, marker1], // 覆盖物数组
false, // 动画过渡到制定位置
[60, 60, 60, 60], // 周围边距,上、下、左、右
10, // 最大 zoom 级别
);
```
Returns **Bounds** bounds 新的地图视口范围
### getFitZoomAndCenterByOverlays
根据 overlays 计算出合适的中心点和 zoom 级别
#### Parameters
- `overlays` **Array<Overlay>** 覆盖物
- `avoid` **Array<Number>** 四周边距,上、下、左、右 (optional, default `[0,0,0,0]`)
- `maxZoom` **Number** 最大 zoom 级别 (optional, default `CoreMap.defaultZooms[1]`)
Returns **\[number, LngLat]** zoom 级别和中心点经纬度
### getFitZoomAndCenterByBounds
根据 bounds 计算出合适的中心点和 zoom 级别
#### Parameters
- `bounds` **(Array<number> | Bounds)** 需要计算的范围
- `avoid` **Array<Number>** 四周边距,上、下、左、右 (optional, default `[0,0,0,0]`)
- `maxZoom` **Number** 最大 zoom 级别 (optional, default `20`)
Returns **\[number, LngLat]** zoom 级别和中心点经纬度
### addControl
添加控件。参数可以是插件列表中的任何插件对象,如:ToolBar、OverView、Scale等 </br>
[相关示例][31]
#### Parameters
- `control` **Control** 控件对象
### removeControl
移除地图上的指定控件 </br>
[相关示例][31]
#### Parameters
- `control` **Control** 控件对象
### setMapStyle
设置地图的显示样式,目前支持两种地图样式: </br>
第一种:自定义地图样式,如 "amap://styles/d6bf8c1d69cea9f5c696185ad4ac4c86" </br>
可前往地图自定义平台定制自己的个性地图样式; </br>
第二种:官方样式模版,如 "amap://styles/grey"。 </br>
其他模版样式及自定义地图的使用说明见 [开发指南][33] </br>
[相关示例][34] </br>
#### Parameters
- `value` **String**
### getMapStyle
获取地图显示样式
### getAllOverlays
返回添加的覆盖物对象,可选类型包括marker、circle、polyline、polygon; </br>
Type可缺省,缺省时返回所有覆盖物(marker、circle、polyline、polygon)。 </br>
返回结果不包含官方覆盖物等,比如定位marker,周边搜索圆等 </br>
[相关示例][35]
#### Parameters
- `type` **String?** 可选,覆盖物类型
Returns **Array<Overlay>** 覆盖物数组
### clearMap
删除地图上所有的覆盖物
### clearInfoWindow
清除地图上的信息窗体。
### getFeatures
获取地图显示元素种类
Returns **Array<String>** 返回 features 的集合,可能有 bg(地图背景)、point(兴趣点)、
road(道路)、building(建筑物)
### setFeatures
设置地图上显示的元素种类,支持bg(地图背景)、point(兴趣点)、 </br>
road(道路)、building(建筑物) </br>
[相关示例][36]
#### Parameters
- `features` **Array<string>** 类型数组
#### Examples
```javascript
map.setFeatures(['bg', 'road']);
```
### setMask
#### Parameters
- `maskPath` **Array<Array<number>>** 掩模范围
- `maskPath` **Array<Number>** 掩模范围
### setLabelRejectMask
设置文字是否拒绝掩模,true:不进行掩模,false:掩模
#### Parameters
- `reject` **boolean** 是否拒绝掩模
### customCoords
### mapStyle
获取审图号
## MapsEvent
此对象用于表示地图、覆盖物、叠加层上的各种鼠标事件返回,包含以下字段:
Type: Object
### Properties
- `lnglat` **LngLat** 发生事件时光标所在处的经纬度坐标。
- `pixel` **Pixel** 发生事件时光标所在处的像素坐标。
- `type` **string** 事件类型。
- `target` **Object** 发生事件的目标对象,不同类型返回target不同。例如,事件对象是Marker,则target表示目标对象为Marker,事件对象是其他,则随之改变。
FILE:references/api/marker.md
## 点标记
用于在地图上添加点状地图要素的类型
## Marker
点标记
### Parameters
- `opts` **MarkerOptions** 点标记参数
- `opts.map` **Map** 要显示该marker的地图对象
- `opts.position` **(Vector2 | LngLat)** 点标记在地图上显示的位置
- `opts.icon` **(Icon \| string)** 在点标记中显示的图标。可以传一个图标地址,也可以传Icon对象。有合法的content内容设置时,此属性无效。
- `opts.content` **(string \| HTMLElement)** 点标记显示内容。可以是HTML要素字符串或者HTML DOM对象。content有效时,icon属性将被覆盖。
- `opts.title` **string** 鼠标滑过点标记时的文字提示。不设置则鼠标滑过点标无文字提示。
- `opts.visible` **boolean** 点标记是否可见,默认值:true
- `opts.zIndex` **number** 点标记的叠加顺序。地图上存在多个点标记叠加时,通过该属性使级别较高的点标记在上层显示,默认zIndex:12
- `opts.offset` **(Vector2 | Pixel)** 点标记显示位置偏移量,默认值为[0,0]。Marker指定position后,默认以marker左上角位置为基准点(若设置了anchor,则以anchor设置位置为基准点),对准所给定的position位置,若需使marker指定位置对准在position处,需根据marker的尺寸设置一定的偏移量。
- `opts.anchor` **(string | Vector2)** 设置点标记锚点,可选值:'top-left','top-center','top-right', 'middle-left', 'center', 'middle-right', 'bottom-left', 'bottom-center', 'bottom-right' [相关示例][72]
- `opts.angle` **number** 点标记的旋转角度,,广泛用于改变车辆行驶方向。默认值:0
- `opts.clickable` **boolean** 点标记是否可点击,默认值: true
- `opts.draggable` **boolean** 设置点标记是否可拖拽移动,默认值:false
- `opts.bubble` **boolean** 事件是否冒泡,默认为 false
- `opts.zooms` **Vector2** 点标记显示的层级范围,超过范围不显示。默认值:zooms: [2, 20]
- `opts.cursor` **string** 指定鼠标悬停时的鼠,默认值:'pointer'
- `opts.topWhenClick` **boolean** 鼠标点击时marker是否置顶,默认false ,不置顶
- `opts.label` **object** 添加文本标注
- `opts.label.content` **string** 文本标注的内容
- `opts.label.offset` **(Pixel | Vector2 | Array<number>)** 为偏移量。如设置了 direction,以 direction 方位为基准点进行偏移。
- `opts.label.direction` **string** 文本标注方位 可选值:'top'|'right'|'bottom'|'left'|'center',默认值: 'right'。
- `opts.extData` **any** 用户自定义属 ,支持JavaScript API任意数据类型,如 Marker的id等。可将自定义数据保存在该属性上,方便后续操作使用。
### Examples
```javascript
var marker = new AMap.Marker({
position: new AMap.LngLat(116.397428, 39.90923),
icon: 'https://a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png',
anchor: 'bottom-center',
});
map.add(marker);
```
### getTitle
获取点标记的文字提示
Returns **(string \| undefined)**
### setTitle
设置鼠标滑过点标记时的文字提示
#### Parameters
- `title` **string** 点标记的文字提示
### getIcon
当点标记未自定义图标时,获取Icon内容
Returns **(Icon \| string \| undefined)**
### setIcon
设置点标记的显示图标,设置了有效 content 则 icon 不生效
#### Parameters
- `icon` **(Icon \| string)** 点标记中显示的图标
### getLabel
获取点标记文本标签内容
Returns **LabelOptions** 文本标签设置项
### setLabel
设置点标记文本标签内容
#### Parameters
- `opts` **LabelOptions**
### getClickable
获取点标记是否支持鼠标单击事件
Returns **boolean**
### setClickable
设置点标记是否支持鼠标单击事件
#### Parameters
- `clickable` **boolean** 默认值: true
### getDraggable
获取点标记对象是否可拖拽移动
Returns **boolean**
### setDraggable
设置点标记对象是否可拖拽移动
#### Parameters
- `draggable` **boolean**
### getTop
获取该点标记是否置顶
Returns **boolean**
### setTop
地图上有多个marker时,设置是否置顶该点标记
#### Parameters
- `isTop` **boolean**
### getCursor
获取鼠标悬停时的光标设置
Returns **string**
### setCursor
设置鼠标悬停时的光标
#### Parameters
- `cursor` **string**
### getExtData
获取用户自定义数据
Returns **(any | undefined)**
### setExtData
设置用户自定义数据
#### Parameters
- `extData` 用户自定义数据
### remove
移除点标记 [相关示例][73]
### moveTo
以给定时长/速度移动点标记到指定位置, 需加载 AMap.MoveAnimation 插件才可使用
#### Parameters
- `targetPosition` **(LngLat | Vector2)** 指定位置
- `opts` **MoveToOptions** moveTo 动画参数
- `opts.duration` **number** 每段动画持续时长, 单位:ms
- `opts.speed` **number** 动画速度,已废弃
- `opts.easing` **EasingCallback** easing 时间函数
- `opts.autoRotation` **boolean** 点标记方向是否沿路径旋转
#### Examples
```javascript
AMap.plugin('AMap.MoveAnimation', function(){
// 加载完 AMap.MoveAnimation 插件以后,创建一个 Marker 实例
const animationMarker = new AMap.Marker({
position: new AMap.LngLat(116.397389,39.909466),
icon: "https://a.amap.com/jsapi_demos/static/demo-center-v2/car.png",
offset: new AMap.Pixel(-13, -26),
});
// 调用 moveTo 方法
animationMarker.moveTo([116.397389, 39.909466], {
duration: 1000,
delay: 500,
});
});
```
### moveAlong
以指定的时长,点标记沿指定的路径移动,加载 AMap.MoveAnimation 后可以使用
JSAPI 2.0 可支持分段设置速度和时长 [相关示例][75]
#### Parameters
- `path` **(Array<LngLat> | Array<Vector2> | Array<MoveAlongObj>)** 路径数组
- `opts` **MoveAlongOptions** moveAlong 动画参数 可选
- `opts.duration` **(number \| AnimationCallback)** 每段动画持续时长, 单位:ms
- `opts.speed` **(number \| AnimationCallback)** 每段动画速度,已废弃
- `opts.easing` **EasingCallback** easing 时间函数
- `opts.circlable` **boolean** 动画是否循环
- `opts.delay` **(number \| AnimationCallback)** 延迟动画时长
- `opts.aniInterval` **number** 每段完整动画间隔时长
- `opts.autoRotation` **boolean** 覆盖物是否沿路径旋转
#### Examples
```javascript
const path = [
new AMap.LngLat(116.397389, 39.909466),
new AMap.LngLat(116.379707, 39.968168),
new AMap.LngLat(116.434467, 39.95001),
new AMap.LngLat(116.46365, 39.979481),
new AMap.LngLat(116.397389, 39.909466),
];
// 分段设置时长
const customData = [
{ position: path[0], duration: 200 },
{ position: path[1], duration: 400 },
{ position: path[2], duration: 600 },
{ position: path[3], duration: 800 },
{ position: path[4], duration: 1000 },
];
AMap.plugin('AMap.MoveAnimation', function(){
// 加载完 AMap.MoveAnimation 插件以后,创建一个 Marker 实例
const animationMarker = new AMap.Marker({
position: new AMap.LngLat(116.397389,39.909466),
angle: 90,
});
// 调用 moveAlong 方法
animationMarker.moveAlong(customData);
});
```
### startMove
开启点标记动画,加载 AMap.MoveAnimation 后创建的点标记可以使用
#### Examples
```javascript
animationMarker.startMove();
```
### stopMove
停止点标记动画,加载 AMap.MoveAnimation 后创建的点标记可以使用
#### Examples
```javascript
animationMarker.stopMove();
```
### pauseMove
暂停点标记动画,加载 AMap.MoveAnimation 后创建的点标记可以使用
#### Examples
```javascript
animationMarker.pauseMove();
```
### resumeMove
重新启动点标记动画,加载 AMap.MoveAnimation 后创建的点标记可以使用
#### Examples
```javascript
animationMarker.resumeMove();
```
### getMap
获取覆盖物的地图实例
Returns **(Map | null)**
### setMap
将覆盖物设置到地图上
#### Parameters
- `map` **(Map | null)**
### addTo
将覆盖物加到地图上
#### Parameters
- `map` **Map**
### add
将覆盖物加到地图上
#### Parameters
- `map` **Map**
### show
显示覆盖物
### hide
隐藏覆盖物
### getPosition
获取覆盖物位置
Returns **any**
### setPosition
设置覆盖物位置
#### Parameters
- `position` **Vector2**
### getAnchor
获取覆盖物锚点
Returns **(string | Vector2 | undefined)**
### Marker
设置覆盖物锚点
#### Parameters
- `anchor` **string**
### getOffset
获取覆盖物偏移量
Returns **(Vector2 | Pixel \| undefined \| Array<number>)**
### setOffset
设置覆盖物偏移量
#### Parameters
- `offset` **(Vector2 | Pixel)**
### getAngle
获取覆盖物旋转角度
Returns **(number \| undefined)**
### setAngle
设置覆盖物旋转角度
#### Parameters
- `angle` **number**
### getSize
如设置了尺寸,获取设置的尺寸
Returns **Vector2**
### setSize
设置尺寸
#### Parameters
- `size` **(Vector2 | Size)**
### getzIndex
获取覆盖物的叠加顺序
Returns **(number \| undefined)**
### setzIndex
设置覆盖物的叠加顺序
#### Parameters
- `zIndex` **number**
### getOptions
获取覆盖物的所有属性
Returns **OverlayOptions**
### getContent
获取点标记显示的自定义内容
Returns **(string \| HTMLElement \| undefined)**
### setContent
设置点标记显示的自定义内容,可以是HTML要素字符串或者HTML DOM对象
#### Parameters
- `content` **(HTMLDOM | string)**
### getBounds
获取点标记范围
Returns **Bounds**
## Text
文本标记
### Parameters
- `opts` **TextOptions** 文本参数
- `opts.map` **Map** 要显示该marker的地图对象
- `opts.position` **(Vector | LngLat)** 点标记在地图上显示的位置
- `opts.text` **LabelOptions** 标记显示的文本内容
- `opts.title` **string** 鼠标滑过点标记时的文字提示
- `opts.visible` **boolean** 点标记是否可见,默认为true
- `opts.zIndex` **number** 点标记的叠加顺序
- `opts.offset` **(Vector | Pixel)** 点标记显示位置偏移量,默认值[0, 0]。[图解说明][78]
- `opts.anchor` **(string | Vector)** 设置点标记锚点。默认值:'center'。可选值:'top-left'|'top-center'|'top-right'|'middle-left'|'center'|'middle-right'|'bottom-left'|'bottom-center'|'bottom-right'
- `opts.angle` **number** 点标记的旋转角度。默认值:0 。注:angle属性是使用CSS3来实现的,支持IE9及以上版本
- `opts.clickable` **boolean** 点标记是否可点击。默认值: true
- `opts.draggable` **boolean** 设置点标记是否可拖拽移动。默认值:false
- `opts.bubble` **boolean** 事件是否冒泡,默认值:false
- `opts.zooms` **Vector** 点标记显示的层级范围,超过范围不显示。默认值:zooms: [2, 20]。
- `opts.cursor` **string** 指定鼠标悬停时的鼠标样式。
- `opts.topWhenClick` **boolean** 鼠标点击时marker是否置顶,默认值: false
- `opts.extData` **any** 用户自定义属性 ,支持JavaScript API任意数据类型,如 Marker的id等。可将自定义数据保存在该属性上,方便后续操作使用。
- `opts.style` **object** 设置文本样式,Object同css样式表,如:{'background-color':'red'}
### Examples
```javascript
var text = new AMap.Text({
position: new AMap.LngLat(116.397428, 39.90923),
anchor: 'bottom-center',
text: '文本标记',
style: {'background-color':'red'},
});
map.add(text);
```
### getText
获取文本标记内容
Returns **(string \| undefined)**
### text
设置文本标记内容
#### Parameters
- `text` **string**
### setStyle
修改文本标记样式。Object同css样式表,如:{'background-color':'red'}
#### Parameters
- `style`
### getTitle
获取文本标记的文字提示
Returns **(string \| undefined)**
### setTitle
设置鼠标滑过文本标记时的文字提示
#### Parameters
- `title` **string** 文本标记的文字提示
### getClickable
获取文本标记是否支持鼠标单击事件
Returns **boolean**
### setClickable
设置文本标记是否支持鼠标单击事件
#### Parameters
- `clickable` **boolean** 默认值: true
### getDraggable
获取文本标记对象是否可拖拽移动
Returns **boolean**
### setDraggable
设置文本标记对象是否可拖拽移动
#### Parameters
- `draggable` **boolean**
### getTop
获取该文本标记是否置顶
Returns **boolean**
### getMap
获取文本标记的地图实例
Returns **(Map | null)**
### setMap
将文本标记设置到地图上
#### Parameters
- `map` **(Map | null)**
### addTo
将文本标记加到地图上,不推荐使用。推荐使用 map.add(text);
#### Parameters
- `map` **Map**
### add
将文本标记加到地图上
#### Parameters
- `map` **Map**
### show
显示文本标记
### hide
隐藏文本标记
### getPosition
获取文本标记位置
Returns **any**
### setPosition
设置文本标记位置
#### Parameters
- `position` **Vector**
### getAnchor
获取文本标记锚点
Returns **(string | Vector | undefined)**
### Text
设置文本标记锚点
#### Parameters
- `anchor` **string**
### getOffset
获取文本标记偏移量
Returns **(Vector | Pixel \| undefined \| Array<number>)**
### setOffset
设置文本标记偏移量,相对 anchor 后的偏移位置
#### Parameters
- `offset` **(Array<number> | Pixel)**
### getAngle
获取文本标记旋转角度
Returns **(number \| undefined)**
### setAngle
设置文本标记旋转角度
#### Parameters
- `angle` **number**
### getzIndex
获取文本标记的叠加顺序
Returns **(number \| undefined)**
### setzIndex
设置文本标记的叠加顺序
#### Parameters
- `zIndex` **number**
### getOptions
获取文本标记的所有属性
Returns **OverlayOptions**
### getBounds
获取文本标记范围
Returns **Bounds**
### moveTo
以给定速度移动文本标记到指定位置, 需加载 AMap.MoveAnimation 插件才可使用
#### Parameters
- `targetPosition` **(LngLat | Vector)** 指定位置
- `opts` **MoveToOptions** moveTo 动画参数
- `opts.duration` **number** 每段动画持续时长, 单位:ms
- `opts.speed` **number** 动画速度,已废弃
- `opts.easing` **EasingCallback** easing 时间函数
- `opts.autoRotation` **boolean** 覆盖物是否沿路径旋转
#### Examples
```javascript
AMap.plugin('AMap.MoveAnimation', function(){
// 加载完 AMap.MoveAnimation 插件以后,创建一个 Text 实例
const animationText = new AMap.Text({
text: '文本标记',
position: new AMap.LngLat(116.397389,39.909466),
});
animationText.moveTo([116.397389, 39.909466], {
duration: 1000,
delay: 500,
});
});
```
### moveAlong
以指定的时长,文本标记沿指定的路径移动,加载 AMap.MoveAnimation 后可以使用
#### Parameters
- `path` **(Array<LngLat> | Array<Vector> | Array<MoveAlongObj>)** 路径数组
- `opts` **MoveAlongOptions** moveAlong 动画参数 可选
- `opts.duration` **(number \| AnimationCallback)** 每段动画持续时长, 单位:ms
- `opts.speed` **(number \| AnimationCallback)** 每段动画速度,已废弃
- `opts.easing` **EasingCallback** easing 时间函数
- `opts.circlable` **boolean** 动画是否循环
- `opts.delay` **(number \| AnimationCallback)** 延迟动画时长
- `opts.aniInterval` **number** 每段完整动画间隔时长
- `opts.autoRotation` **boolean** 覆盖物是否沿路径旋转
#### Examples
```javascript
const path = [
new AMap.LngLat(116.397389, 39.909466),
new AMap.LngLat(116.379707, 39.968168),
new AMap.LngLat(116.434467, 39.95001),
new AMap.LngLat(116.46365, 39.979481),
new AMap.LngLat(116.397389, 39.909466),
];
const customData = [
{ position: path[0], duration: 200 },
{ position: path[1], duration: 400 },
{ position: path[2], duration: 600 },
{ position: path[3], duration: 800 },
{ position: path[4], duration: 1000 },
];
AMap.plugin('AMap.MoveAnimation', function(){
// 加载完 AMap.MoveAnimation 插件以后,创建一个 Text 实例
const animationText = new AMap.Text({
text: '文本标记',
position: new AMap.LngLat(116.397389,39.909466),
});
animationText.moveAlong(customData);
});
```
### startMove
开启文本标记动画,加载 AMap.MoveAnimation 后可以使用
#### Examples
```javascript
animationText.startMove();
```
### stopMove
停止文本标记动画,加载 AMap.MoveAnimation 后可以使用
#### Examples
```javascript
animationText.stopMove();
```
### pauseMove
暂停文本标记动画,加载 AMap.MoveAnimation 后可以使用
#### Examples
```javascript
animationText.pauseMove();
```
### resumeMove
重新启动文本标记动画,加载 AMap.MoveAnimation 后可以使用
#### Examples
```javascript
animationText.resumeMove();
```
### setTop
地图上有多个marker时,设置是否置顶该文本标记
#### Parameters
- `isTop` **boolean**
### getCursor
获取鼠标悬停时的光标设置
Returns **string**
### setCursor
设置鼠标悬停时的光标
#### Parameters
- `cursor` **string**
### getExtData
获取用户自定义数据
Returns **(any | undefined)**
### setExtData
设置用户自定义数据
#### Parameters
- `extData` 用户自定义数据
### remove
移除点标记
## Icon
### Parameters
- `opts`
## Icon
## LabelMarker
标注类
### Parameters
- `opts` **LabelMarkerOptions** 标注参数
- `opts.name` **string** 标注名称,作为标注标识,并非最终在地图上显示的文字内容,显示文字内容请设置 opts.text.content
- `opts.position` **(Vector2 | LngLat)** 标注位置
- `opts.zooms` **Vector2** 标注显示级别范围, 可选值:[2,20]
- `opts.opacity` **number** 标注透明度,默认值: 1
- `opts.rank` **number** 避让优先级,获取标注的优先级,该优先级用于 labelsLayer 支持避让时,rank 值大的标注会避让掉 rank 值低的标注。默认值:1
- `opts.zIndex` **number** 同一 LabelsLayer 内标注显示层级,数字越大越靠前,默认值: 1
- `opts.visible` **boolean** 标注是否可见, 默认值: true
- `opts.extData` **any** 用户自定义类型数据,可将自定义数据保存在该属性上,方便后续操作使用。
- `opts.icon` **IconOptions** 标注图标设置
- `opts.icon.image` **string** 图标 url。
- `opts.icon.size` **(Vector2 | Size)** 图标大小,默认值:[36, 36]
- `opts.icon.clipOrigin` **(Vector2 | Pixel)** 图标所在图片偏移位置,默认值: [0, 0]
- `opts.icon.clipSize` **(Vector2 | Size)** 图标所在图片裁剪大小,若未设置,则使用图片大小
- `opts.icon.anchor` **(Vector2 | Pixel \| string)** 图标锚点,锚点位置对应设置的 position 位置。可选值:'top-left'| 'top-center'|'top-right'|'middle-left'|'center'| 'middle-right'| 'bottom-left'| 'bottom-center'| 'bottom-right' 。默认值:'top-left'。
- `opts.text` **TextOptions** 标注文本设置
- `opts.text.content` **string** 文本标注的内容,该属性为直接显示在标注上的文本内容。
- `opts.text.direction` **string** 文本标注方位。若设置了 icon,则 direction 是以 icon 为中心的偏移,若未设置 icon,则相对 position 偏移。
可选值:'top'|'right'|'bottom'|'left'|'center'。默认值: right
- `opts.text.offset` **(Pixel | Vector2)** 为偏移量,在 direction 基础上的偏移。默认值[0, 0]
- `opts.text.zooms` **Vector2** 文本显示级别范围,可单独设置文本显示范围
- `opts.text.style` **TextStyleOptions** 文本样式设置
- `opts.text.style.fontSize` **number** 文字大小,默认值: 12
- `opts.text.style.fillColor` **string** 文字颜色
- `opts.text.style.strokeColor` **string** 文字描边颜色
- `opts.text.style.padding` **(string \| Array<(string \| number)>)** 文字 padding。默认值:[3, 3, 3, 3]
- `opts.text.style.backgroundColor` **string** 文字背景颜色
- `opts.text.style.borderColor` **string** 文字背景描边颜色
- `opts.text.style.borderWidth` **number** 文字背景描边粗细
- `opts.text.style.fold` **boolean** 文字是否折行(6个字一折行)
### Examples
```javascript
// 创建一个 LabelMarker 实例
var labelMarker = new AMap.LabelMarker({
position: [116.468599, 39.995847],
opacity: 1,
zIndex: 2,
icon: {
image: 'https://a.amap.com/jsapi_demos/static/images/poi-marker.png',
anchor: 'bottom-center',
size: [25, 34],
clipOrigin: [459, 92],
clipSize: [50, 68]
},
text: {
content: '香猪坊',
direction: 'right',
style: {
fontSize: 15,
fillColor: '#fff',
strokeColor: 'rgba(255,0,0,0.5)',
strokeWidth: 2,
padding: [3, 10],
backgroundColor: 'yellow',
borderColor: '#ccc',
borderWidth: 3,
}
}
});
// 创建一个 LabelsLayer 实例来承载 LabelMarker,[LabelsLayer 文档](https://lbs.amap.com/api/jsapi-v2/documentation#labelslayer)
var labelsLayer = new LabelsLayer({
collision: true,
});
// 将 LabelMarker 实例添加到 LabelsLayer 上
labelsLayer.add(labelMarker);
// 将 LabelsLayer 添加到地图上
map.add(labelsLayer);
```
### getName
获取标注的名称,作为标注标识,并非最终在地图上显示的文字内容
Returns **(string \| undefined)**
### setName
设置标注的名称,作为标注标识,并非最终在地图上显示的文字内容
#### Parameters
- `name` **string**
### getPosition
获取标注的显示位置
Returns **LngLat**
### setPosition
设置标注的位置
#### Parameters
- `position` **(LngLat | \[number] | string)**
### getZooms
获取标注显示级别范围
Returns **(Vector2 | undefined)**
### setZooms
设置显示级别范围
#### Parameters
- `zooms` **\[number]**
### getOpacity
获取标注透明度值
Returns **(number \| undefined)**
### setOpacity
设置标注透明度
#### Parameters
- `opacity` **number**
### setRotation
设置标注旋转角度
#### Parameters
- `angle` **number** 旋转角度
### getRotation
获取标注旋转角度
Returns **(number \| `0`)** 旋转角度
### getzIndex
获取标注的叠加顺序
Returns **(number \| undefined)**
### setzIndex
设置标注的叠加顺序
#### Parameters
- `zIndex` **number**
### getRank
获取标注的优先级,该优先级用于 labelsLayer 支持避让时,rank 值大的标注会避让掉 rank 值低的标注。
Returns **(number \| undefined)**
### setRank
设置标注的优先级,该优先级用于 labelsLayer 支持避让时,rank 值大的标注会避让掉 rank 值低的标注。
#### Parameters
- `rank` **number**
### getText
获取标注的文本设置
Returns **(LabelMarkerTextOptions | undefined)**
### setText
设置标注的文本设置,可设置显示的文字内容和文字样式等
#### Parameters
- `textOpts` **LabelMarkerTextOptions**
### getIcon
获取标注的图标设置
Returns **(LabelMarkerIconOptions | undefined)**
### setIcon
设置标注的图标设置,可设置显示的标注图片
#### Parameters
- `iconOpts` **LabelMarkerIconOptions**
### getOptions
获取标注的全部属性配置
Returns **LabelMarkerOptions**
### getExtData
获取用户自定义属性
Returns **(any | undefined)**
### setExtData
设置用户自定义属性
#### Parameters
- `extData`
### setTop
是否设置置顶标注,设置为 true 表示该标注会显示在所有标注之前
#### Parameters
- `isTop` **boolean**
### setVisible
设置该标注的可见性
#### Parameters
- `visible` **boolean**
### getVisible
获取该标注的可见性
Returns **(boolean \| undefined)**
### getCollision
获取该标注是否被避让,从而没有显示
Returns **(boolean \| undefined)**
### show
标注显示
### hide
标注隐藏
### remove
将自身从标注层移除
### getStatus
获取函数执行状态时间节点
Returns **Array<string>**
### moveTo
以给定速度移动标注到指定位置, 需加载 AMap.MoveAnimation 插件才可使用
#### Parameters
- `targetPosition` **(LngLat | Vector2)** 指定位置
- `opts` **MoveToOptions** moveTo 动画参数
- `opts.duration` **number** 每段动画持续时长, 单位:ms
- `opts.speed` **number** 动画速度,已废弃
- `opts.easing` **EasingCallback** easing 时间函数
- `opts.autoRotation` **boolean** 覆盖物是否沿路径旋转
#### Examples
```javascript
AMap.plugin('AMap.MoveAnimation', function(){
// 加载完 AMap.MoveAnimation 插件以后,创建一个 LabelMarker 实例
const animationLabel = new AMap.LabelMarker({
content: '标注',
position: new AMap.LngLat(116.397389,39.909466),
text: {
content: '动画标注'
}
});
labelsLayer.add(animationLabel);
// 调用 moveTo 方法
animationLabel.moveTo([116.397389, 39.909466], {
duration: 1000,
delay: 500,
});
});
```
### moveAlong
以指定的时长,标注沿指定的路径移动,加载 AMap.MoveAnimation 后可以使用
#### Parameters
- `path` **(Array<LngLat> | Array<Vector2> | Array<MoveAlongObj>)** 路径数组
- `opts` **MoveAlongOptions** moveAlong 动画参数 可选
- `opts.duration` **(number \| AnimationCallback)** 每段动画持续时长, 单位:ms
- `opts.speed` **(number \| AnimationCallback)** 每段动画速度,已废弃
- `opts.easing` **EasingCallback** easing 时间函数
- `opts.circlable` **boolean** 动画是否循环
- `opts.delay` **(number \| AnimationCallback)** 延迟动画时长
- `opts.aniInterval` **number** 每段完整动画间隔时长
- `opts.autoRotation` **boolean** 覆盖物是否沿路径旋转
#### Examples
```javascript
const path = [
new AMap.LngLat(116.397389, 39.909466),
new AMap.LngLat(116.379707, 39.968168),
new AMap.LngLat(116.434467, 39.95001),
new AMap.LngLat(116.46365, 39.979481),
new AMap.LngLat(116.397389, 39.909466),
];
const customData = [
{ position: path[0], duration: 200 },
{ position: path[1], duration: 400 },
{ position: path[2], duration: 600 },
{ position: path[3], duration: 800 },
{ position: path[4], duration: 1000 },
];
AMap.plugin('AMap.MoveAnimation', function(){
// 加载完 AMap.MoveAnimation 插件以后,创建一个 LabelMarker 实例
const animationLabel = new AMap.LabelMarker({
content: '标注',
position: new AMap.LngLat(116.397389,39.909466),
text: {
content: '动画标注'
}
});
labelsLayer.add(animationLabel);
// 调用 moveAlong 方法
animationLabel.moveAlong(customData);
});
```
### startMove
开启标注动画,加载 AMap.MoveAnimation 后创建的标注可以使用
#### Examples
```javascript
animationLabel.startMove();
```
### stopMove
停止标注动画,加载 AMap.MoveAnimation 后创建的标注可以使用
#### Examples
```javascript
animationLabel.stopMove();
```
### pauseMove
暂停标注动画,加载 AMap.MoveAnimation 后创建的标注可以使用
#### Examples
```javascript
animationLabel.pauseMove();
```
### resumeMove
重新启动标注动画,加载 AMap.MoveAnimation 后创建的标注可以使用
#### Examples
```javascript
animationLabel.resumeMove();
```
### richText
设置富文本
#### Parameters
- `richText` **any**
### richText
获取富文本属性信息
Returns **any**
## ElasticMarker
灵活点标记
### Parameters
- `opts` **ElasticMarkerOptions** 灵活点标记参数
- `opts.map` **Map** 要显示该marker的地图对象
- `opts.position` **(Vector | LngLat)** 点标记在地图上显示的位置
- `opts.visible` **boolean** 点标记是否可见,默认为true
- `opts.zIndex` **number** 点标记的叠加顺序
- `opts.offset` **(Vector | Pixel)** 点标记显示位置偏移量
- `opts.clickable` **boolean** 点标记是否可点击
- `opts.draggable` **boolean** 设置点标记是否可拖拽移动
- `opts.bubble` **boolean** 事件是否冒泡,默认为 false
- `opts.cursor` **string** 指定鼠标悬停时的鼠标样式
- `opts.topWhenClick` **boolean** 鼠标点击时marker是否置顶
- `opts.zoomStyleMapping` **Record<string, number>** 表示地图级别与styles中样式的映射,{14:0,15:0,16:1,17:1,}表示14到15级使用styles中的第0个样式,16-17级使用第二个样式
- `opts.extData` **any** 用户自定义属性
- `opts.styles` **Array<ElasticStyle>** 多个不同样式的数组
- `opts.styles.icon` **ElasticIcon** 灵活标注图标样式类型
- `opts.styles.icon.img` **string** 图标 url
- `opts.styles.icon.size` **Vector** 图标显示大小
- `opts.styles.icon.anchor` **(Vector | string)** 图标锚点
- `opts.styles.icon.imageOffset` **(Vector | string)** 图片偏移量
- `opts.styles.icon.imageSize` **number** 图片大小
- `opts.styles.icon.fitZoom` **number** 最合适的级别,在此级别下显示为原始大小
- `opts.styles.icon.scaleFactor` **number** 地图放大一级的缩放比例系数
- `opts.styles.icon.maxScale` **number** 最大放大比例
- `opts.styles.icon.minScale` **number** 最小放大比例
- `opts.styles.label` **ElasticLabel** 灵活标注文本样式类型
- `opts.styles.label.content` **ElasticLabel** 文本内容
- `opts.styles.label.position` **ElasticLabel** 文本位置相对于图标的基准点,可选值:BL、BM、BR、ML、MR、TL、TM、TR分别代表左下角、底部中央、右下角、左侧中央、右侧中央、左上角、顶部中央、右上角
- `opts.styles.label.offset` **ElasticLabel** 相对position的偏移量
- `opts.styles.label.minZoom` **ElasticLabel** label的最小显示级别
### Examples
```javascript
// 样式列表
var stylesArr = [{
icon: {
img: 'https://a.amap.com/jsapi_demos/static/resource/img/men3.png',
size: [16, 16],//可见区域的大小
anchor: 'bottom-center',//锚点
fitZoom: 14,//最合适的级别
scaleFactor: 2,//地图放大一级的缩放比例系数
maxScale: 2,//最大放大比例
minScale: 1//最小放大比例
},
label: {
content: '百花殿',
position: 'BM',
minZoom: 15
}
}, {
icon: {
img: 'https://a.amap.com/jsapi_demos/static/resource/img/tingzi.png',
size: [48, 63],
anchor: 'bottom-center',
fitZoom: 17.5,
scaleFactor: 2,
maxScale: 2,
minScale: 0.125
},
label: {
content: '万寿亭',
position: 'BM',
minZoom: 15
}
}];
zoom 与样式的映射
var zoomStyleMapping1 = {
14: 0, // 14级使用样式 0
15: 0,
16: 0,
17: 0,
18: 1,
19: 1,
20: 1,
};
// 加载灵活点标记的插件
AMap.plugin(['AMap.ElasticMarker'], function(){
var elasticMarker = new AMap.ElasticMarker({
position: [116.405562, 39.881166],
// 指定样式列表
styles: stylesArray,
// 指定 zoom 与样式的映射
zoomStyleMapping: zoomStyleMapping,
});
map.add(elasticMarker);
});
```
### getTitle
获取获取灵活点标记标记的文字提示
Returns **(string \| undefined)**
### setTitle
设置鼠标滑过灵活点标记时的文字提示
#### Parameters
- `title` **string** 灵活点标记的文字提示
### getClickable
获取灵活点标记是否支持鼠标单击事件
Returns **boolean**
### setClickable
设置灵活点标记是否支持鼠标单击事件
#### Parameters
- `clickable` **boolean** 默认值: true
### getMap
获取覆盖物的地图实例
Returns **(Map | null)**
### setMap
将覆盖物设置到地图上
#### Parameters
- `map` **(Map | null)**
### show
显示覆盖物
### hide
隐藏覆盖物
### getPosition
获取覆盖物位置
Returns **any**
### setPosition
设置灵活点标记位置
#### Parameters
- `position` **Vector**
### setAnchor
设置灵活点标记锚点
#### Parameters
- `anchor` **string**
### getzIndex
获取覆盖物的叠加顺序
Returns **(number \| undefined)**
### setzIndex
设置覆盖物的叠加顺序
#### Parameters
- `zIndex` **number**
### getOptions
获取覆盖物的所有属性
Returns **OverlayOptions**
### getBounds
Returns **Bounds**
### getDraggable
获取灵活点标记对象是否可拖拽移动
Returns **boolean**
### setDraggable
设置灵活点标记对象是否可拖拽移动
#### Parameters
- `draggable` **boolean**
### getTop
获取该灵活点标记是否置顶
Returns **boolean**
### setTop
地图上有多个marker时,设置是否置顶该灵活点标记
#### Parameters
- `isTop` **boolean**
### getCursor
获取鼠标悬停时的光标设置
Returns **string**
### setCursor
设置鼠标悬停时的光标
#### Parameters
- `cursor` **string**
### getExtData
获取用户自定义数据
Returns **(any | undefined)**
### setExtData
设置用户自定义数据
#### Parameters
- `extData` 用户自定义数据
### remove
移除点标记
## MarkerCluster
用于展示大量点标记,将点标记按照距离进行聚合,以提高绘制性能。点聚合支持用户自定义样式,以插件形式调用。
### Parameters
- `map` **Map** 要添加点聚合的地图对象
- `dataOptions` **Array** 需要进行聚合显示的点数据
- `dataOptions.lnglat` **Array** 点标记的经纬度信息
- `dataOptions.weight` **number** 点标记的权重信息,以权重高的点为中心进行聚合
- `MarkerClusterOptions` **Object** 点聚合属性设置
- `MarkerClusterOptions.gridSize` **Number** 聚合计算时网格的像素大小,默认60
- `MarkerClusterOptions.maxZoom` **Number** 最大的聚合级别,大于该级别就不进行相应的聚合。默认值为 18,即小于 18 级的级别均进行聚合,18 及以上级别不进行聚合
- `MarkerClusterOptions.averageCenter` **Boolean** 聚合点的图标位置是否是所有聚合内点的中心点。默认为 true。数据中如果含有权重值,以权重高的点为中心进行聚合
- `MarkerClusterOptions.clusterByZoomChange` **Boolean** 地图缩放过程中是否聚合。默认值 false。
- `MarkerClusterOptions.styles` **Array<Object>** <div>
<div>指定聚合后的点标记的图标样式,可缺省,缺省时为默认样式</div>
<div>数据元素分别对应聚合量在1-10,11-100,101-1000…的聚合点的样式;</div>
<div>当用户设置聚合样式少于实际叠加的点数,未设置部分按照系统默认样式显示;</div>
<div>单个图标样式包括以下几个属性:</div>
<div>1. {string} url:图标显示图片的url地址(必选)</div>
<div>2. {AMap.Size} size:图标显示图片的大小(必选)</div>
<div>3. {AMap.Pixel} offset:图标定位在地图上的位置相对于图标左上角的偏移值。默认为(0,0),不偏移(可选)</div>
<div>4. {AMap.Pixel} imageOffset:图片相对于可视区域的偏移值,此功能的作用等同CSS中的background-position属性。默认为(0,0),不偏移(可选)</div>
<div>5. {String} textColor:文字的颜色,默认为"#000000"(可选)</div>
<div>6. {Number} textSize:文字的大小,默认为10(可选)</div>
</div>
- `MarkerClusterOptions.renderClusterMarker` **function** <div>
<div>该方法用来实现聚合点的自定义绘制,由开发者自己实现,API 将在绘制每个聚合点的时候调用这个方法,可以实现聚合点样式的灵活设定,指定了 renderClusterMarker 后 styles 无效。</div>
<div>该函数的入参为一个Object,包含如下属性:</div>
<div>1. count: 当前聚合点下聚合的 Marker 的数量</div>
<div>2. marker: 当前聚合点显示的 Marker</div>
</div>
- `MarkerClusterOptions.renderMarker` **function** <div>
<div>该方法用来实现非聚合点的自定义绘制,由开发者自己实现,API 将在绘制每个非聚合点的时候调用这个方法</div>
<div>该函数的入参为一个Object,包含如下属性:</div>
<div>marker: 非聚合点 Marker 对象</div>
</div>
### Examples
```javascript
// 数据格式为一组含有经纬度信息的数组,如下所示。其中【经纬度】lnglat 为必填字段,【权重】weight 为可选字段。
var points = [
{ weight: 8, lnglat: ["108.939621", "34.343147"] },
{ weight: 1, lnglat: ["112.985037", "23.15046"] },
{ weight: 1, lnglat: ["110.361899", "20.026695"] },
{ weight: 1, lnglat: ["121.434529", "31.215641"] }
];
// 加载点聚合插件
map.plugin(["AMap.MarkerCluster"],function(){
var cluster = new AMap.MarkerCluster(map, points, {
gridSize: 80 // 聚合网格像素大小
});
});
```
### addData
在原数据基础上添加数据,格式同 dataOptions
#### Parameters
- `dataOptions` **dataOptions**
### setData
设置数据,格式同 dataOptions
#### Parameters
- `dataOptions` **dataOptions**
### getClustersCount
获取聚合点的总数量
Returns **Number**
### getGridSize
获取聚合网格的像素大小
Returns **Number**
### setGridSize
设置聚合网格的像素大小
#### Parameters
- `size` **Number** 像素大小
### getMaxZoom
获取地图中点标记的最大聚合级别
Returns **Number**
### setMaxZoom
设置地图中点标记的最大聚合级别
#### Parameters
- `zoom` **Number** 级别
### setStyles
设置样式聚合点,格式同 opts.styles
#### Parameters
- `Map` **Map**
### getStyles
获取样式
Returns **Array**
### getMap
获取地图对象
Returns **Map**
### setMap
设置地图对象
#### Parameters
- `Map` **Map**
### isAverageCenter
获取单个聚合点位置是否是聚合内所有标记的平均中心
Returns **Boolean**
### setAverageCenter
设置聚合点位置是否是所有聚合点的中心
#### Parameters
- `averageCenter` **Boolean**
## MassMarks
**Extends AMap.Event**
海量点类
### Parameters
- `data` **Array<MassData>** 海量点数据参数
- `data.lnglat` **LngLat** 经纬度
- `data.style` **number** 样式索引值
- `opts` **Array<MassMarkersOptions>** 海量点参数
- `opts.zIndex` **number** 图标 url
- `opts.opacity` **number** 图标显示大小
- `opts.zooms` **Vector2** 旋转角度
- `opts.cursor` **string** 锚点位置
- `opts.style` **(MassMarkersStyleOptions | Array<MassMarkersStyleOptions>)** 点展示优先级
- `opts.style.url` **string** 图标 url
- `opts.style.size` **(Vector2 | Size)** 图标显示大小
- `opts.style.rotation` **number** 旋转角度
- `opts.style.anchor` **Pixel** 锚点位置
- `opts.style.zIndex` **number** 点展示优先级,默认为使用样式的索引值。
### Examples
```javascript
// 创建 MassMarks 实例,[亲手试一试](https://lbs.amap.com/api/jsapi-v2/example/marker/massmarks)
var massMarks = new AMap.MassMarks(data, {
opacity: 0.8,
zIndex: 111,
cursor: 'help',
style: style,
});
// 将海量点实例添加到地图上
map.add(massMarks);
```
### setMap
设置显示MassMark的地图对象
#### Parameters
- `map` **Map**
### getMap
获取Marker所在地图对象
Returns **any**
### getData
输出MassMark的数据集,数据结构同setDatas中的数据集
Returns **Array<MassData>**
### setData
设置MassMark展现的数据集
#### Parameters
- `data` **Array<MassData>**
### getStyle
获取MassMark的显示样式
Returns **Array<MassMarkersStyleOptions>**
### setStyle
设置MassMark的显示样式,可设置单个样式或样式列表,每条数据通过设置的样式索引值获取对应样式
#### Parameters
- `style` **(MassMarkersStyleOptions | Array<MassMarkersStyleOptions>)**
### setOpacity
获取海量点图层的透明度
Returns **number**
### setzIndex
设置海量点图层透明度
#### Parameters
- `opacity` **number** 透明度
### setzIndex
设置海量点图层叠加顺序
#### Parameters
- `zIndex` **number** 叠加顺序
### getzIndex
获取海量点图层的透明度
Returns **number**
### getZooms
获取海量点图层可见层级范围
Returns **Vector2**
### setZooms
设置海量点图层可见层级范围
#### Parameters
- `zooms` **Vector2** 可见层级范围
### show
显示海量点图层
### hide
隐藏海量点图层
### clear
清除海量点
## MoveAnimation
用于实现点标记沿线段或者路径轨迹移动的动画基类,可用于满足轨迹回放、实时轨迹等场景。MoveAnimation无需单独声明或初始化,Marker、Text、LabelMarker均已继承了 MoveAnimation的实现。
### moveTo
以给定时间移动点标记到指定位置,加载 AMap.MoveAnimation 后可以使用
#### Parameters
- `targetPosition` **(LngLat | Vector)** 指定位置
- `opts` **MoveToOptions** moveTo 动画参数
- `opts.duration` **number** 每段动画持续时长, 单位:ms
- `opts.speed` **number** 动画速度,已废弃
- `opts.easing` **EasingCallback** easing 时间函数
- `opts.autoRotation` **boolean** 覆盖物是否沿路径旋转
#### Examples
```javascript
AMap.plugin('AMap.MoveAnimation', function(){
const animationMarker = new AMap.Marker({
position: new AMap.LngLat(116.397389,39.909466),
});
animationMarker.moveTo([116.397389, 39.909466], {
duration: 1000,
delay: 500,
});
});
```
### moveAlong
以指定的时长,点标记沿指定的路径移动,加载 AMap.MoveAnimation 后可以使用
#### Parameters
- `path` **(Array<LngLat> | Array<Vector> | Array<MoveAlongObj>)** 路径数组
- `opts` **MoveAlongOptions** moveAlong 动画参数 可选
- `opts.duration` **(number \| AnimationCallback)** 每段动画持续时长, 单位:ms
- `opts.speed` **(number \| AnimationCallback)** 每段动画速度,已废弃
- `opts.easing` **EasingCallback** easing 时间函数
- `opts.circlable` **boolean** 动画是否循环
- `opts.delay` **(number \| AnimationCallback)** 延迟动画时长
- `opts.aniInterval` **number** 每段完整动画间隔时长
- `opts.autoRotation` **boolean** 覆盖物是否沿路径旋转
#### Examples
```javascript
const path = [
new AMap.LngLat(116.397389, 39.909466),
new AMap.LngLat(116.379707, 39.968168),
new AMap.LngLat(116.434467, 39.95001),
new AMap.LngLat(116.46365, 39.979481),
new AMap.LngLat(116.397389, 39.909466),
];
const customData = [
{ position: path[0], duration: 200 },
{ position: path[1], duration: 400 },
{ position: path[2], duration: 600 },
{ position: path[3], duration: 800 },
{ position: path[4], duration: 1000 },
];
AMap.plugin('AMap.MoveAnimation', function(){
const animationMarker = new AMap.Marker({
position: new AMap.LngLat(116.397389,39.909466),
angle: 90,
});
animationMarker.moveAlong(customData);
});
```
### startMove
开启点标记动画,加载 AMap.MoveAnimation 后可以使用
#### Examples
```javascript
animationMarker.startMove();
```
### stopMove
停止点标记动画,加载 AMap.MoveAnimation 后可以使用
#### Examples
```javascript
animationMarker.stopMove();
```
### resumeMove
重新启动点标记动画,加载 AMap.MoveAnimation 后可以使用
#### Examples
```javascript
animationMarker.resumeMove();
```
## AnimationCallback
MoveAnimation 回调函数
Type: function
### Parameters
- `index` **number** 运行到点的索引
- `data` **LngLat** 当前点经纬度
Returns **number**
## EasingCallback
时间函数回调
Type: function
### Parameters
- `passedTime` **number** 已经过去的时长
Returns **number**
FILE:references/api/overlay-group.md
## 群组
用于批量操作图层和覆盖物的群组类型,可以简化代码书写
## LayerGroup
LayerGroup类用来包装其它图层类的实例, 对实例集合做批量操作, 避免开发者对多个需要设置同样属性的图层实例做循环处理。</br>
同时只要对LayerGroup执行过setMap方法后, 新添加到该LayerGroup中的图层会自动将其map属性修改到该group对应的map,</br>
此外从group中移除该图层时,也会将该图层从group对应的map中移除。</br>
如果对图层集合添加对某个事件的监听或解除监听, 图层集合会对集合中所有图层实例做集合处理, </br>
只要该图层支持此事件, 该事件绑定/解除即对图层生效
[相关示例][86]
### Parameters
- `layers` **Array<Layer>** 图层数组
### setMap
添加到地图上面
#### Parameters
- `map` **Map** 地图对象
Returns **any**
### hasLayer
判断传入的图层实例是否在集合中
#### Parameters
- `layer` **Layer**
### setOptions
修改图层属性(包括线样式、样色等等)
#### Parameters
- `opts` **LayerOptions** 参数
- `opts.visible` **Boolean** 是否可见
- `opts.opacity` **Number** 透明度
- `opts.zIndex` **Number** 层级
- `opts.zooms` **Array<Number>** 集合可见范围
Returns **any**
### eachLayer
对集合中的图层做迭代操作,其中iterator的函数定义是:</br>
function(layer, index, collections),相关含义如下:</br>
layer: 当前迭代到的图层 </br>
index: 该图层在集合中的序列号(从0开始) </br>
collections: 所有图层实例 </br>
#### Parameters
- `iterator` **Function**
### addLayer
添加单个图层到集合中,不支持添加重复的图层
#### Parameters
- `layer` **Layer** 图层对象
### addLayers
添加图层数组到集合中,不支持添加重复的图层
#### Parameters
- `layers` **Array<Layer>** 图层数组
### removeLayer
从集合中删除传入的图层实例
#### Parameters
- `layer` **Layer** 图层对象
### removeLayers
从集合中删除传入的图层实例数组
#### Parameters
- `layers` **Array<Layer>** 图层数组
### getLayers
获取组里所有对象,包括图层和覆盖物
Returns **Array<Layers>**
### clearLayers
清空图层
### hide
设置图层隐藏
### show
设置图层可见
### on
事件批量绑定
#### Parameters
- `type` **String** 事件名称, 比如: click、mouseover
- `事件回调函数` **Function**
### reload
重新加载图层资源,重新渲染
Returns **any**
## OverlayGroup
OverlayGroup 类用来包装其它覆盖物类的实例,对实例集合做整体操作,避免开发者对多个需要设置同样属性的覆盖物实例做循环处理。
此外从group中移除该覆盖物时,也会将该覆盖物从group对应的map中移除。
目前OverlayGroup支持Marker, Polygon, Polyline, Circle,CircleMarker, Rectangle, Ellipse 和 BezierCurve。
### Parameters
- `overlays` **Array<Overlay>**
### addOverlay
添加单个覆盖物到集合中,不支持添加重复的覆盖物
#### Parameters
- `overlay` **Overlay**
### type
### className
### addOverlays
添加覆盖物数组到集合中,不支持添加重复的覆盖物
#### Parameters
- `overlays` **Array<Overlay>**
### getOverlays
返回当前集合中所有的覆盖物
Returns **Array**
### hasOverlay
判断传入的覆盖物实例是否在集合中
#### Parameters
- `overlay` **Overlay**
Returns **boolean**
### removeOverlay
从集合中删除传入的覆盖物实例
#### Parameters
- `overlay` **Overlay**
### removeOverlays
从集合中删除传入的覆盖物实例数组
#### Parameters
- `overlays` **Array**
### clearOverlays
清空集合
### eachOverlay
对集合中的覆盖物做迭代操作,其中iterator的函数定义是:
function(overlay, index, collections),相关含义如下:
overlay: 当前迭代到的覆盖物
index: 该覆盖物在集合中的序列号(从0开始)
collections: 所有覆盖物实例
#### Parameters
- `iterator` **Function**
### show
在地图上显示集合中覆盖物
### hide
在地图上隐藏集合中覆盖物
### setOptions
修改覆盖物属性(包括线样式、样色等等)
#### Parameters
- `opt` **Object**
FILE:references/api/routing.md
## 路线规划
用于驾车、货车、骑行、步行、公交等的路线规划查询
## Driving
驾车路线规划服务,提供起、终点坐标的驾车导航路线[查询功能][109]。AMap. Driving构造函数的参数为 DrivingOptions 对象。DrivingOptions 允许设置驾车策略和返回信息详略。用户可以通过自定义回调函数取回并显示查询结果。若服务请求失败,系统将返回错误信息
### Parameters
- `opts` **DrivingOptions** 参数信息
- `opts.map` **Map** AMap.Map对象, 展现结果的地图实例。当指定此参数后,搜索结果的标注、线路等均会自动添加到此地图上。可选
- `opts.policy` **number?** [驾车路线规划策略][110]
- `opts.extensions` **string** 默认值:base,返回基本地址信息\\n当取值为:all,返回DriveStep基本信息+DriveStep详细信息 (optional, default `'base'`)
- `opts.ferry` **number** 默认为0,表示可以使用轮渡,为1的时候表示不可以使用轮渡 (optional, default `0`)
- `opts.panel` **(string \| HTMLElement)?** 结果列表的HTML容器id或容器元素,提供此参数后,结果列表将在此容器中进行展示。可选
- `opts.hideMarkers` **boolean** 设置隐藏路径规划的起始点图标
设置为true:隐藏图标;设置false:显示图标\\n默认值为:false (optional, default `false`)
- `opts.showTraffic` **boolean?** 设置是否显示实时路况信息,默认设置为true。
显示绿色代表畅通,黄色代表轻微拥堵,红色代表比较拥堵,灰色表示无路况信息。
- `opts.province` **string?** 车牌省份的汉字缩写,用于判断是否限行,与number属性组合使用,可选。例如:京
- `opts.number` **string?** 除省份之外车牌的字母和数字,用于判断限行相关,与province属性组合使用,可选。例如:NH1N11
- `opts.isOutline` **boolean?** 使用map属性时,绘制的规划线路是否显示描边。缺省为true
- `opts.outlineColor` **string?** 使用map属性时,绘制的规划线路的描边颜色。缺省为'white'
- `opts.autoFitView` **boolean?** 用于控制在路径规划结束后,是否自动调整地图视野使绘制的路线处于视口的可见范围
### Examples
```javascript
var driving;
mapObj.plugin(["AMap.Driving"], function() { //加载驾车服务插件
var drivingOptions = {
//驾车策略,包括 LEAST_TIME,LEAST_FEE, LEAST_DISTANCE,REAL_TRAFFIC
policy: AMap.DrivingPolicy.LEAST_TIME
};
driving = new AMap.Driving(drivingOptions);
AMap.Event.addListener(driving, "complete", driving_CallBack); //返回导航查询结果
//根据起终点坐标规划驾车路线
MDrive.search(new AMap.LngLat(116.379018, 39.865026), new AMap.LngLat(116.42732, 39.903752));
});
```
### search
根据起点、终点和途经点(可选)坐标或名称,实现驾车路线规划,途经点通过opts设定
#### Parameters
- `origin` **LngLat** 起点经纬度
- `destination` **LngLat** 终点经纬度
- `opts` **Object**
- `opts.waypoints` **Array<LngLat>** 途径点,最多支持16个
- `callback` **DrivingCallback** status为complete时,result为DrivingResult;当status为error时,result为错误信息info;当status为no_data时,代表检索返回0结果。
### search
根据起点、终点和途经点(可选)坐标或名称,实现驾车路线规划,途经点通过opts设定
#### Parameters
- `points` **Array<Object>** 终点经纬度points为起点、终点和途经点(可选)名称及对应城市的数组,例如:
[{keyword:‘北京南站’,city:‘北京市’},{keyword:‘广东大厦’,city:’北京市’},{ keyword:‘北京西站’,city:‘北京市’}]
系统取数组第一个元素和最后一个元素作为起点和终点,中间元素为途经点;
- `callback` **DrivingCallback** status为complete时,result为DrivingResult;当status为error时,result为错误信息info;当status为no_data时,代表检索返回0结果。
### clear
清除搜索结果
### setAvoidPolygons
设置避让区域,最大支持三个避让区域,参数为LngLat的二维数组
#### Parameters
- `areas` **Array<Array<LngLatLike>>**
### clearAvoidPolygons
清除避让区域
### getAvoidPolygons
获取避让区域,返回LngLat的二维数组
Returns **Array<Array<LngLat>>** 避让区域
### setAvoidRoad
设置避让道路名称,只支持一条避让道路
注:避让道路和避让区域不能同时使用
#### Parameters
- `value` **string**
### clearAvoidRoad
清除避让道路
### getAvoidRoad
获取避让道路
Returns **string**
### setProvinceAndNumber
设置车牌的汉字首字符和首字后的号码,设置后路线规划的结果将考虑该车牌在当前时间的限行路段
#### Parameters
- `province` **string**
- `number` **string**
### setPolicy
设置驾车路线规划策略
#### Parameters
- `policy` **Object** 驾车路线规划策略
## DrivingCallback
Driving.search 的回调函数
Type: Function
### Parameters
- `status` **string** status为complete时,result为DrivingResult;当status为error时,result为错误信息info;当status为no_data时,代表检索返回0结果
- `result` **(info | DrivingResult)**
## DrivingResult
DrivingResult 对象
Type: Object
### Properties
- `info` **string** 成功状态说明
- `origin` **LngLat** 驾车规划起点坐标
- `destination` **LngLat** 驾车规划终点坐标
- `start` **Poi** 驾车规划起点
- `end` **Poi** 驾车规划终点
- `waypoints` **Poi** 驾车规划途经点
- `taxi_cost` **number** 打车费用,仅extensions为“all”时返回. 单位: 元
- `routes` **Array<DriveRoute>** 驾车规划路线列表
- `routes.route` **DriveRoute** 驾车规划路线列表元素
- `routes.route.distance` **number** 起点到终点的驾车距离,单位:米
- `routes.route.time` **number** 时间预计,单位:秒
- `routes.route.policy` **string** 驾车规划策略
- `routes.route.tolls` **number** 此驾车路线收费金额,单位:元
- `routes.route.tolls_distance` **number** 收费路段长度,单位:米
- `routes.route.restriction` **number** 限行结果,0 代表限行已规避或未限行,即该路线没有限行路段,1 代表限行无法规避,即该线路有限行路段
- `steps` **Array<(DriveStepBasic \| DriveStepDetail)>** 子路段DriveStep集合
## DriveStepBasic
DriveStep 对象(基本信息)
Type: Object
### Properties
- `start_location` **LngLat** 此路段起点
- `end_location` **LngLat** 此路段终点
- `instruction` **string** 此路段说明,如“沿北京南站路行驶565米右转”
- `action` **string** 本驾车子路段完成后动作
- `assist_action` **string** 驾车子路段完成后辅助动作,一般为到达某个目的地时返回
- `orientation` **string** 驾车方向
- `road` **string** 驾车方向
- `distance` **number** 此路段距离,单位:米
- `tolls` **number** 此段收费,单位:元
- `tolls_distance` **number** 收费路段长度,单位:米
- `toll_road` **string** 主要收费道路
- `time` **number** 此路段预计使用时间,单位:秒
- `path` **Array<LngLat>** 此路段坐标集合
## DriveStepDetail
DriveStep 对象(详细信息)
Type: Object
### Properties
- `cities` **Array<ViaCity>** 途径城市列表
- `cities.city` **ViaCity** 途径城市列表元素
- `cities.city.name` **string** 途径名称
- `cities.city.citycode` **string** 城市编码
- `cities.city.adcode` **string** 区域编码
- `cities.city.districts` **Array<District>** 途径行政区列表
- `cities.city.districts.district` **District** 途径行政区列表元素
- `cities.city.districts.district.name` **string** 区域名称
- `cities.city.districts.district.adcode` **string** 区域编码
- `tmcs` **Array<TMC>** 实时交通信息列表
- `tmcs.tmc` **TMC** 实时交通信息列表元素
- `tmcs.tmc.lcode` **string** 路况信息对应的编码
如果direction是正向 lcode返回值大于0;否则lcode,返回值小于0;
如果返回0则说明此路段无lcode
- `tmcs.tmc.distance` **number** 此lcode对应的路段长度,单位: 米
- `tmcs.tmc.status` **string** 路况状态,可能的值有:未知,畅通,缓行,拥堵
## TruckDriving
驾车路线规划服务,提供起、终点坐标的驾车导航路线[查询功能][115]。AMap. Driving构造函数的参数为 DrivingOptions 对象。DrivingOptions 允许设置驾车策略和返回信息详略。用户可以通过自定义回调函数取回并显示查询结果。若服务请求失败,系统将返回[错误信息][116]
### Parameters
- `opts` **TruckDrivingOptions** 参数信息
- `opts.map` **Map** AMap.Map对象, 展现结果的地图实例。当指定此参数后,搜索结果的标注、线路等均会自动添加到此地图上。可选
- `opts.policy` **number?** [货车路线规划策略strategy][117]
- `opts.size` **number** 车型大小,必填,1-4分别对应小型至大型
- `opts.width` **number** 宽度,缺省2.5米 (optional, default `2.5`)
- `opts.height` **number** 高度,缺省1.6米 (optional, default `1.6`)
- `opts.load` **number** 载重,缺省0.9t (optional, default `0.9`)
- `opts.weight` **number** 自重,缺省10t (optional, default `10`)
- `opts.axlesNum` **number** 轴数,缺省2轴 (optional, default `2`)
- `opts.extensions` **string** 默认值:base,返回基本地址信息\\n当取值为:all,返回DriveStep基本信息+DriveStep详细信息 (optional, default `'base'`)
- `opts.panel` **(string \| HTMLElement)?** 结果列表的HTML容器id或容器元素,提供此参数后,结果列表将在此容器中进行展示。可选
- `opts.hideMarkers` **boolean** 设置隐藏路径规划的起始点图标
设置为true:隐藏图标;设置false:显示图标\\n默认值为:false (optional, default `false`)
- `opts.showTraffic` **boolean?** 设置是否显示实时路况信息,默认设置为true。
显示绿色代表畅通,黄色代表轻微拥堵,红色代表比较拥堵,灰色表示无路况信息。
- `opts.province` **string?** 车牌省份的汉字缩写,用于判断是否限行,与number属性组合使用,可选。例如:京
- `opts.number` **string?** 除省份之外车牌的字母和数字,用于判断限行相关,与province属性组合使用,可选。例如:NH1N11
- `opts.isOutline` **boolean?** 使用map属性时,绘制的规划线路是否显示描边。缺省为true
- `opts.outlineColor` **string?** 使用map属性时,绘制的规划线路的描边颜色。缺省为'white'
- `opts.autoFitView` **boolean?** 用于控制在路径规划结束后,是否自动调整地图视野使绘制的路线处于视口的可见范围
### Examples
```javascript
var driving;
mapObj.plugin(["AMap.TruckDriving"], function() { //加载驾车服务插件
var drivingOptions = {
//驾车策略,包括 LEAST_TIME,LEAST_FEE, LEAST_DISTANCE,REAL_TRAFFIC
policy: AMap.DrivingPolicy.LEAST_TIME
};
driving = new AMap.TruckDriving(drivingOptions);
AMap.Event.addListener(driving, "complete", driving_CallBack); //返回导航查询结果
//根据起终点坐标规划驾车路线
MDrive.search(new AMap.LngLat(116.379018, 39.865026), new AMap.LngLat(116.42732, 39.903752));
});
```
```javascript
var TruckDriving;
mapObj.plugin(["AMap.TruckDriving"], function() { //加载驾车服务插件
var TruckDrivingOptions = {
//驾车策略,包括 LEAST_TIME,LEAST_FEE, LEAST_DISTANCE,REAL_TRAFFIC
policy: AMap.TruckDrivingPolicy.LEAST_TIME
};
TruckDriving = new AMap.TruckDriving(TruckDrivingOptions);
AMap.Event.addListener(TruckDriving, "complete", TruckDriving_CallBack); //返回导航查询结果
//根据起终点坐标规划驾车路线
MDrive.search(new AMap.LngLat(116.379018, 39.865026), new AMap.LngLat(116.42732, 39.903752));
});
```
### clear
清除搜索结果
### search
根据起点、终点和途经点(可选)坐标或名称,实现驾车路线规划,途经点通过opts设定
#### Parameters
- `locations` **Array<Truck~Location>** 途经点列表
- `locations.location` **Truck~Location** 某一个途经点
- `locations.location.lnglat` **\[number, number]** 经纬度
- `locations.location.pid` **string** POI ID,可缺省
- `locations.location.type` **string** POI类型,可缺省
- `callback` **DrivingCallback** status为complete时,result为TruckResult;当status为error时,result为错误信息info;当status为no_data时,代表检索返回0结果。
### search
根据起点、终点和途经点(可选)坐标或名称,实现驾车路线规划,途经点通过opts设定
#### Parameters
- `points` **Array<Truck~Path>** 途经点列表 例如 : [{keyword:'北京站',city:'010'},//起点
{keyword:'北京西站',city:'010'},//途径
{keyword:'北京大学',city:'010'}//终点
]
- `points.point` **Truck~Path** 某个途经点
- `points.point.keyworkd` **string** 关键字
- `points.point.city` **string** 城市code
- `callback` **DrivingCallback** status为complete时,result为TruckResult;当status为error时,result为错误信息info;当status为no_data时,代表检索返回0结果。
### setProvinceAndNumber
修改车牌号
#### Parameters
- `province` **string**
- `number` **number**
### setPolicy
设置驾车路线规划策略,参考opts.policy
#### Parameters
- `policy` **Object** 驾车路线规划策略,参考opts.policy
## Walking
步行路线规划服务,提供起、终点坐标的驾车导航路线[查询功能][119]。AMap. Driving构造函数的参数为 DrivingOptions 对象。DrivingOptions 允许设置驾车策略和返回信息详略。用户可以通过自定义回调函数取回并显示查询结果。若服务请求失败,系统将返回[错误信息][116]
### Parameters
- `opts` **WalkingOptions** 参数信息
- `opts.map` **Map** AMap.Map对象, 展现结果的地图实例。当指定此参数后,搜索结果的标注、线路等均会自动添加到此地图上。可选
- `opts.panel` **(string \| HTMLElement)?** 结果列表的HTML容器id或容器元素,提供此参数后,结果列表将在此容器中进行展示。可选
- `opts.hideMarkers` **boolean** 设置隐藏路径规划的起始点图标
设置为true:隐藏图标;设置false:显示图标\\n默认值为:false
显示绿色代表畅通,黄色代表轻微拥堵,红色代表比较拥堵,灰色表示无路况信息。 (optional, default `false`)
- `opts.isOutline` **boolean?** 使用map属性时,绘制的规划线路是否显示描边。缺省为true
- `opts.outlineColor` **string?** 使用map属性时,绘制的规划线路的描边颜色。缺省为'white'
- `opts.autoFitView` **boolean?** 用于控制在路径规划结束后,是否自动调整地图视野使绘制的路线处于视口的可见范围
### Examples
```javascript
var mwalk;
mapObj.plugin(["AMap.Walking"], function() { //加载步行导航插件
mwalk = new AMap.Walking (); //构造步行导航类
AMap.event.addListener(mwalk, "complete", walking_CallBack); //返回导航查询结果
//根据起、终点坐标规划步行路线
mwalk.search(new AMap.LngLat(116.379018, 39.865026), new AMap.LngLat(116.42732, 39.903752));
});
```
```javascript
var mwalk;
mapObj.plugin(["AMap.Walking"], function() { //加载步行导航插件
mwalk = new AMap.Walking (); //构造步行导航类
AMap.Event.addListener(mwalk, "complete", walking_CallBack); //返回导航查询结果
//根据起、终点坐标规划步行路线
mwalk.search(new AMap.LngLat(116.379018, 39.865026), new AMap.LngLat(116.42732, 39.903752));
});
```
### clear
清除搜索的结果
### search
根据起点、终点坐标,实现步行路线规划
#### Parameters
- `origin` **LngLat** 起点经纬度
- `destination` **LngLat** 终点经纬度
- `callback` **WalkingCallback** status为complete时,result为 WalkingResult;当status为error时,result为错误信息info;当status为no_data时,代表检索返回0结果。
### search
根据起点、终点名称,实现步行路线规划
#### Parameters
- `points` **Array<Object>** 终点经纬度points为起点、终点和途经点(可选)名称及对应城市的数组,例如:
[{keyword:‘方恒国际中心A座’},{keyword:‘望京站’}]
系统取数组第一个元素和最后一个元素作为起点和终点,中间元素为途经点;
- `callback` **WalkingCallback** status为complete时,result为 WalkingResult;当status为error时,result为错误信息info;当status为no_data时,代表检索返回0结果。
## WalkingCallback
Walking.search 的回调函数
Type: Function
### Parameters
- `status` **string** status为complete时,result为 WalkingResult;当status为error时,result为错误信息info;当status为no_data时,代表检索返回0结果
- `result` **(info | WalkingResult)**
## WalkingResult
WalkingResult 对象
Type: Object
### Properties
- `info` **string** 成功状态说明
- `origin` **LngLat** 步行规划起点坐标
- `destination` **LngLat** 步行规划终点坐标
- `start` **Poi** 步行规划起点
- `end` **Poi** 步行规划终点
- `count` **number** 步行导航路段数目
- `routes` **Array<WalkRoute>** 步行规划路线列表
- `routes.distance` **number** 起点到终点总步行距离,单位:米
- `routes.time` **number** 步行时间预计,单位:秒
- `routes.steps` **Array<WalkStep>** 路段列表,以道路名称作为分段依据,将整个步行导航方案分隔成若干路段
- `routes.steps.instruction` **string** 步行子路段描述,规则:沿 road步行 distance 米 action,例:”沿北京站街步行351米”
- `routes.steps.distance` **number** 步行子路段距离,单位:米
- `routes.steps.time` **number** 步行子路段预计使用时间,单位:秒
- `routes.steps.path` **Array<LngLat>** 步行子路段坐标集合
- `routes.steps.road` **string** 道路
- `routes.steps.action` **string** 本步行子路段完成后动作
- `routes.steps.assist_action` **string** 步行子路段完成后辅助动作,一般为到达某个公交站点或目的地时返回
## Transfer
公交换乘服务,提供起始点公交路线规划服务,目前公交换乘仅支持同一城市的公交路线规划,跨城市出行规划请参考驾车导航查询。公交换乘查询返回结果整合步行信息,若换乘路段(Segment)换乘类型为地铁 “SUBWAY”,则至少包含一条地铁口信息(SubwayEntrance)。用户可以通过自定义回调函数取回并显示查询结果。若服务请求失败,系统将返回错误信息。
### Parameters
- `opts` **DrivingOptions** 参数信息
- `opts.map` **Map** AMap.Map对象, 展现结果的地图实例。当指定此参数后,搜索结果的标注、线路等均会自动添加到此地图上。可选
- `opts.city` **string** 公交换乘的城市,支持城市名称、城市区号、电话区号,此项为必填
- `opts.policy` **number** [公交换乘策略strategy][122]
- `opts.nightflag` **boolean** 是否计算夜班车,默认为不计算。true:计算,false:不计算 (optional, default `false`)
- `opts.extensions` **string** 默认值:base,返回基本地址信息\\n当取值为:all,返回DriveStep基本信息+DriveStep详细信息 (optional, default `'base'`)
- `opts.panel` **(string \| HTMLElement)?** 结果列表的HTML容器id或容器元素,提供此参数后,结果列表将在此容器中进行展示。可选
- `opts.hideMarkers` **boolean** 设置隐藏路径规划的起始点图标
设置为true:隐藏图标;设置false:显示图标\\n默认值为:false (optional, default `false`)
- `opts.isOutline` **boolean?** 使用map属性时,绘制的规划线路是否显示描边。缺省为true
- `opts.outlineColor` **string?** 使用map属性时,绘制的规划线路的描边颜色。缺省为'white'
- `opts.autoFitView` **boolean?** 用于控制在路径规划结束后,是否自动调整地图视野使绘制的路线处于视口的可见范围
### Examples
```javascript
var trans;
mapObj.plugin(["AMap.Transfer"], function() { //加载公交换乘插件
transOptions = {
city: '北京市', //公交城市
policy: AMap.TransferPolicy.LEAST_TRANSFER //乘车策略
};
trans = new AMap.Transfer (transOptions); //构造公交换乘类
AMap.Event.addListener(trans, "complete", trans_CallBack); //返回导航查询结果
AMap.Event.addListener(trans, "error", function(e){alert(e.info);}); //返回错误信息
//根据起、终点坐标查询公交换乘路线
trans.search(new AMap.LngLat(116.379018, 39.865026), new AMap.LngLat(116.42732, 39.903752));
});
```
### search
根据起点和终点坐标,进行公交换乘查询
#### Parameters
- `origin` **LngLat** 起点经纬度
- `destination` **LngLat** 终点经纬度
- `callback` **TransferCallback** status为complete时,result为DrivingResult;当status为error时,result为错误信息info;当status为no_data时,代表检索返回0结果。
### search
根据起点和终点坐标,进行公交换乘查询
#### Parameters
- `points` **Array<Object>** 当根据起、终点名称查询时,point为包含起点、终点的数组,例:
[{keyword:‘北京南站’},{keyword:‘北京西站’}]
当数组超过两个元素时,取前两个元素为起点、终点,其余元素忽略
- `callback` **TransferCallback** status为complete时,result为DrivingResult;当status为error时,result为错误信息info;当status为no_data时,代表检索返回0结果。
### leaveAt
设置公交路径规划出发时间
#### Parameters
- `time` **string**
- `date` **string**
### clear
清除结果显示
### setPolicy
设置公交换乘策略
#### Parameters
- `policy` **TransferPolicy** 公交换乘策略
### setCity
设置公交换乘查询的城市
#### Parameters
- `city` **String** 城市
### setCityd
设置公交换乘查询的目的地城市
#### Parameters
- `cityd` **String** 城市
## TransferCallback
Transfer.search 的回调函数 [相关示例][124]
Type: Function
### Parameters
- `status` **string** 当status为complete时,result为TransferResult;
当status为error时,result为错误信息info;
当status为no_data时,代表检索返回0结果
- `result` **(info | TransferResult)**
## TransferResult
TransferResult 对象 [详细文档][122],查阅rest接口 '返回结果参数说明'
Type: Object
## Riding
骑行路线规划服务,提供起、终点坐标的驾车导航路线[查询功能][119]。AMap. Driving构造函数的参数为 DrivingOptions 对象。DrivingOptions 允许设置驾车策略和返回信息详略。用户可以通过自定义回调函数取回并显示查询结果。若服务请求失败,系统将返回[错误信息][116]
### Parameters
- `opts` **RidingOptions** 参数信息
- `opts.map` **Map** AMap.Map对象, 展现结果的地图实例。当指定此参数后,搜索结果的标注、线路等均会自动添加到此地图上。可选
- `opts.policy` **number** 骑行路线规划策略;默认值:0可选值为:
0:推荐路线及最快路线综合
1:推荐路线
2:最快路线 (optional, default `0`)
- `opts.panel` **(string \| HTMLElement)?** 结果列表的HTML容器id或容器元素,提供此参数后,结果列表将在此容器中进行展示。可选
- `opts.hideMarkers` **boolean** 设置隐藏路径规划的起始点图标
设置为true:隐藏图标;设置false:显示图标\\n默认值为:false
显示绿色代表畅通,黄色代表轻微拥堵,红色代表比较拥堵,灰色表示无路况信息。 (optional, default `false`)
- `opts.isOutline` **boolean?** 使用map属性时,绘制的规划线路是否显示描边。缺省为true
- `opts.outlineColor` **string?** 使用map属性时,绘制的规划线路的描边颜色。缺省为'white'
- `opts.autoFitView` **boolean?** 用于控制在路径规划结束后,是否自动调整地图视野使绘制的路线处于视口的可见范围
### Examples
```javascript
var mwalk;
mapObj.plugin(["AMap.Riding"], function() { //加载步行导航插件
mwalk = new AMap.Riding (); //构造步行导航类
AMap.Event.addListener(mwalk, "complete", riding_CallBack); //返回导航查询结果
//根据起、终点坐标规划步行路线
mwalk.search(new AMap.LngLat(116.379018, 39.865026), new AMap.LngLat(116.42732, 39.903752));
});
```
### clear
清除搜索的结果
### setPolicy
骑行路线规划策略
#### Parameters
- `policy` **number** 可选值为:
0:推荐路线及最快路线综合
1:推荐路线
2:最快路线
### search
根据起点、终点坐标,实现骑行路线规划
#### Parameters
- `origin` **LngLat** 起点经纬度
- `destination` **LngLat** 终点经纬度
- `callback` **RidingCallback** status为complete时,result为 RidingResult;当status为error时,result为错误信息info;当status为no_data时,代表检索返回0结果。
### search
根据起点、终点名称,实现骑行路线规划
#### Parameters
- `points` **Array<Object>** 包含起点、终点的数组,例:[{keyword:‘方恒国际中心A座’},{keyword:‘望京站’}]
当数组超过两个元素时,取前两个元素为起点、终点,其余元素忽略;
- `callback` **RidingCallback** status为complete时,result为 RidingResult;当status为error时,result为错误信息info;当status为no_data时,代表检索返回0结果。
## RidingCallback
Riding.search 的回调函数
Type: Function
### Parameters
- `status` **string** status为complete时,result为 RidingResult;当status为error时,result为错误信息info;当status为no_data时,代表检索返回0结果
- `result` **(info | RidingResult)**
## RidingResult
RidingResult [详细文档][128],查阅rest接口'返回结果参数说明'
Type: Object
## DragRoute
### Parameters
- `map` **Map** 指定的地图对象
- `path` **Array<LngLat>** 导航的起点、途经点、终点的经纬度坐标数组
- `policy` **String** [指定驾车策略][110]
- `opts` **DragRouteOptions** 配置项
- `opts.polyOption` **PolylineOptions?** 设置拖拽路线插件的路线属性对象,包括线样式、宽度、颜色等,参考PolylineOptions列表
- `opts.startMarkerOptions` **MarkerOptions?** 设置拖拽路线插件起点点标记属性对象,包括点标记样式、大小等,参考MarkerOptions列表
- `opts.midMarkerOptions` **MarkerOptions?** 设置拖拽路线插件途经点点标记属性对象,包括点标记样式、大小等,参考MarkerOptions列表
- `opts.endMarkerOptions` **MarkerOptions?** 设置拖拽路线插件终点点标记属性对象,包括点标记样式、大小等,参考MarkerOptions列表
- `opts.showTraffic` **boolean** 设置显示实时路况信息,true:路线中显示实时路况信息,false:关闭实时路况信息。 默认值:true (optional, default `true`)
### Examples
```javascript
var arr = new Array();//经纬度坐标数组
arr.push(new AMap.LngLat("116.403322","39.920255")); //初始的导航起点
arr.push(new AMap.LngLat("116.420703","39.897555")); //初始的导航途经点
arr.push(new AMap.LngLat("116.430703","39.897555")); //初始的导航途经点
arr.push(new AMap.LngLat("116.410703","39.897555")); //初始的导航终点
AMap.plugin(['AMap.DragRoute'],function(){
dragRoute = new AMap.DragRoute(mapObj, arr, AMap.DrivingPolicy.LEAST_FEE);
dragRoute.search(); //查询导航路径并开启拖拽导航
});
```
### search
开始路径导航。支持鼠标拖拽导航路径节点,更改途经点时,系统实时重新计算并显示导航路径
### getWays
返回除了起点和终点之外的所有点返回导航的所有途经点,即所有途径点的坐标数组
Returns **Array<LngLat>** 所有途经点坐标
### getRoute
返回当前导航路径,即导航路径的经纬度坐标数组
Returns **Array<LngLat>** 当前导航路径
### destroy
销毁拖拽导航插件。
## DragRouteTruck
可拖拽货车路径规划
### Parameters
- `map` **Map** 指定的地图对象
- `opts` **DragRouteTruckOptions** 配置项
- `opts.polyOption` **PolylineOptions?** 设置拖拽路线插件的路线属性对象,包括线样式、宽度、颜色等,参考PolylineOptions列表
- `opts.startMarkerOptions` **MarkerOptions?** 设置拖拽路线插件起点点标记属性对象,包括点标记样式、大小等,参考MarkerOptions列表
- `opts.midMarkerOptions` **MarkerOptions?** 设置拖拽路线插件途经点点标记属性对象,包括点标记样式、大小等,参考MarkerOptions列表
- `opts.endMarkerOptions` **MarkerOptions?** 设置拖拽路线插件终点点标记属性对象,包括点标记样式、大小等,参考MarkerOptions列表
- `opts.showTraffic` **boolean** 设置显示实时路况信息,true:路线中显示实时路况信息,false:关闭实时路况信息。 默认值:true (optional, default `true`)
- `opts.policy` **number?** 驾车路线规划策略
1躲避拥堵
2不走高速
3避免收费
4躲避拥堵且不走高速
5避免收费且不走高速
6躲避拥堵且避免收费
7躲避拥堵且避免收费且不走高速
8高速优先
9躲避拥堵且高速优先
- `opts.size` **number** 车型大小,必填,1-4分别对应小型至大型
- `opts.width` **number** 宽度,缺省2.5米 (optional, default `2.5`)
- `opts.height` **number** 高度,缺省1.6米 (optional, default `1.6`)
- `opts.load` **number** 载重,缺省0.9t (optional, default `0.9`)
- `opts.weight` **number** 自重,缺省10t (optional, default `10`)
- `opts.axlesNum` **number** 轴数,缺省2轴 (optional, default `2`)
- `opts.extensions` **string** 默认值:base,返回基本地址信息\\n当取值为:all,返回DriveStep基本信息+DriveStep详细信息 (optional, default `'base'`)
- `opts.panel` **(string \| HTMLElement)?** 结果列表的HTML容器id或容器元素,提供此参数后,结果列表将在此容器中进行展示。可选
- `opts.hideMarkers` **boolean** 设置隐藏路径规划的起始点图标
设置为true:隐藏图标;设置false:显示图标\\n默认值为:false (optional, default `false`)
- `opts.showTraffic` **boolean?** 设置是否显示实时路况信息,默认设置为true。
显示绿色代表畅通,黄色代表轻微拥堵,红色代表比较拥堵,灰色表示无路况信息。
- `opts.province` **string?** 车牌省份的汉字缩写,用于判断是否限行,与number属性组合使用,可选。例如:京
- `opts.number` **string?** 除省份之外车牌的字母和数字,用于判断限行相关,与province属性组合使用,可选。例如:NH1N11
- `opts.isOutline` **boolean?** 使用map属性时,绘制的规划线路是否显示描边。缺省为true
- `opts.outlineColor` **string?** 使用map属性时,绘制的规划线路的描边颜色。缺省为'white'
- `opts.autoFitView` **boolean?** 用于控制在路径规划结束后,是否自动调整地图视野使绘制的路线处于视口的可见范围
- `opts.cartype` **number** 车辆类型 0:普通货车(默认值)1:纯电动货车 2:插电混动货车 (optional, default `0`)
- `opts.showpolyline` **number** 是否返回路线数据 当取值为1时,steps与tmcs下的polyline数据会正常返回;当取值为0时,steps与tmcs下的polyline数据为空。 (optional, default `1`)
- `opts.nosteps` **number** 是否返回steps字段内容 当取值为0时,steps字段内容正常返回;当取值为1时,steps字段内容为空。 (optional, default `1`)
- `opts.autoRefresh` **boolean** 是否拖拽后自动更新驾车轨迹 (optional, default `true`)
- `opts.refreshTime` **number** 拖拽后自动更新的延迟时间 (optional, default `300`)
- `opts.apiVersion` **number** 货车接口版本支持 'v4','v5' (optional, default `'v4'`)
- `opts.showFields` **string?** 仅 v5货车接口版本支持 1、具体可指定返回的字段类请见下方返回结果说明中的“show_fields”内字段类型;
2、多个字段间采用“,”进行分割;
3、show_fields未设置时,只返回基础信息类内字段;
4、目前取值支持以下四种:"toll_gate","cameras","general","incident";
"toll_gate":收费站信息
"cameras":电子眼信息
"general":交通设施信息
"incident":交通事件信息
### Examples
```javascript
var arr = new Array();//经纬度坐标数组
path.push({ lnglat: [116.303843, 39.983412] });//起点
path.push({ lnglat: [116.321354, 39.896436] });//途径
path.push({ lnglat: [116.407012, 39.992093] });//终点
AMap.plugin(['AMap.DragRouteTruck'],function(){
dragRoute = new AMap.DragRouteTruck(mapObj, opts);
dragRoute.search(path); //查询导航路径并开启拖拽导航
});
```
### setAvoidPolygons
设置避让区域,最大支持三个避让区域,参数为LngLat的二维数组
#### Parameters
- `areas` **Array<Array<LngLatLike>>**
### clearAvoidPolygons
清除避让区域
### getAvoidPolygons
获取避让区域,返回LngLat的二维数组
Returns **Array<Array<LngLat>>** 避让区域
### search
开始路径导航。支持鼠标拖拽导航路径节点,更改途经点时,系统实时重新计算并显示导航路径
#### Parameters
- `locations` : Array<{lnglat:LngLatLike}>
### updatePath
手动更新路径。设置 autoRefresh 为 false 之后,通过调用这个方法来手动更新路径规划
### getWays
返回除了起点和终点之外的所有点返回导航的所有途经点,即所有途径点的坐标数组
Returns **Array<LngLat>** 所有途经点坐标
### getRoute
返回当前导航路径,即导航路径的经纬度坐标数组
Returns **Array<LngLat>** 当前导航路径
### destroy
销毁拖拽导航插件。
### setOption
修改配置项
#### Parameters
- `opts` **Object**
- `opts.policy` **number?** 驾车路线规划策略
1躲避拥堵
2不走高速
3避免收费
4躲避拥堵且不走高速
5避免收费且不走高速
6躲避拥堵且避免收费
7躲避拥堵且避免收费且不走高速
8高速优先
9躲避拥堵且高速优先
- `opts.size` **number** 车型大小,必填,1-4分别对应小型至大型
- `opts.width` **number** 宽度,缺省2.5米 (optional, default `2.5`)
- `opts.height` **number** 高度,缺省1.6米 (optional, default `1.6`)
- `opts.load` **number** 载重,缺省0.9t (optional, default `0.9`)
- `opts.weight` **number** 自重,缺省10t (optional, default `10`)
- `opts.axlesNum` **number** 轴数,缺省2轴 (optional, default `2`)
- `opts.extensions` **string** 默认值:base,返回基本地址信息\\n当取值为:all,返回DriveStep基本信息+DriveStep详细信息 (optional, default `'base'`)
- `opts.panel` **(string \| HTMLElement)?** 结果列表的HTML容器id或容器元素,提供此参数后,结果列表将在此容器中进行展示。可选
- `opts.hideMarkers` **boolean** 设置隐藏路径规划的起始点图标
设置为true:隐藏图标;设置false:显示图标\\n默认值为:false (optional, default `false`)
- `opts.showTraffic` **boolean?** 设置是否显示实时路况信息,默认设置为true。
显示绿色代表畅通,黄色代表轻微拥堵,红色代表比较拥堵,灰色表示无路况信息。
- `opts.province` **string?** 车牌省份的汉字缩写,用于判断是否限行,与number属性组合使用,可选。例如:京
- `opts.number` **string?** 除省份之外车牌的字母和数字,用于判断限行相关,与province属性组合使用,可选。例如:NH1N11
- `opts.isOutline` **boolean?** 使用map属性时,绘制的规划线路是否显示描边。缺省为true
- `opts.outlineColor` **string?** 使用map属性时,绘制的规划线路的描边颜色。缺省为'white'
- `opts.autoFitView` **boolean?** 用于控制在路径规划结束后,是否自动调整地图视野使绘制的路线处于视口的可见范围
- `opts.cartype` **number** 车辆类型 0:普通货车(默认值)1:纯电动货车 2:插电混动货车 (optional, default `0`)
- `opts.showpolyline` **number** 是否返回路线数据 当取值为1时,steps与tmcs下的polyline数据会正常返回;当取值为0时,steps与tmcs下的polyline数据为空。 (optional, default `1`)
- `opts.nosteps` **number** 是否返回steps字段内容 当取值为0时,steps字段内容正常返回;当取值为1时,steps字段内容为空。 (optional, default `1`)
## GraspRoad
**Extends AMap.Event**
轨迹纠偏服务插件。用于将一组带方向的、可能偏离道路的经纬度轨迹,纠正为准确沿着道路的一条经纬度路径。比如根据间隔采集的车辆位置和朝向信息生成行驶轨迹
### driving
用于驾车轨迹的纠偏。
#### Parameters
- `OriginPath` **Array<Object>**
- `OriginPath.x` **number** 经度
- `OriginPath.y` **number** 纬度
- `OriginPath.ag` **number** 与正北方向的顺时针夹角,[ 0, 360 ]
- `OriginPath.tm` **number** 轨迹点采集的时间,以s为单位 OriginPath数组第一个元素的tm值为从1970年开始的unix的时间戳,精确到秒。
其余元素的tm值为当前采集点的时间减去第一个元素的采集时间的差值
- `OriginPath.sp` **number** 轨迹点的速度,单位 km/h,小数、整数均可
- `callback` **GraspRoadCallback** 回调函数
## GraspRoadCallback
Type: Function
### Parameters
- `err` **Object** 正确时为空
- `GraspedPath` **Object** 返回数据,[详查rest文档][131]
- `GraspedPath.distance` **number** 总距离
- `GraspedPath.data` **Object**
- `GraspedPath.data.points` **Array<Object>** 轨迹点数据
- `GraspedPath.data.points.x` **number** 经度
- `GraspedPath.data.points.x` **number** 纬度
FILE:references/api/search.md
## 搜索
用于进行 POI 搜索联想与数据查询的相关类型
## AutoComplete
根据输入关键字提示匹配信息,可将Poi类型和城市作为输入提示的限制条件。用户可以通过自定义回调函数取回并显
### Parameters
- `opts` **object** 输入提示参数
- `opts.type` **string** 输入提示时限定POI类型,多个类型用“|”分隔,目前只支持Poi类型编码如“050000” 默认值:所有类别
- `opts.city` **string** 输入提示时限定城市。可选值:城市名(中文或中文全拼)、citycode、adcode;默认值:“全国”
- `opts.datatype` **string** 返回的数据类型。可选值:all-返回所有数据类型、poi-返回POI数据类型、bus-返回公交站点数据类型、busline-返回公交线路数据类型目前暂时不支持多种类型
- `opts.citylimit` **boolean** 是否强制限制在设置的城市内搜索,默认值为:false,true:强制限制设定城市,false:不强制限制设定城市
- `opts.input` **(string \| HTMLDivElement)** 可选参数,用来指定一个input输入框,设定之后,在input输入文字将自动生成下拉选择列表。支持传入输入框DOM对象的id值,或直接传入输入框的DOM对象。
- `opts.output` **(string \| HTMLDivElement)** 可选参数,指定一个现有的div的id或者元素,作为展示提示结果的容器,当指定了input的时候有效,缺省的时候将自动创建一个显示结果面板
- `opts.outPutDirAuto` **boolean** 默认为true,表示是否在input位于页面较下方的时候自动将输入面板显示在input上方以避免被遮挡
- `opts.closeResultOnScroll` **boolean** 页面滚动时关闭搜索结果列表,默认 true
- `opts.lang` **string** 设置检索语言类型,默认中文 'zh_cn'
### Examples
```javascript
var auto;
//加载输入提示插件
map.plugin(['AMap. Autocomplete'], function() {
let autoOptions = {
city: '010' //城市,默认全国
};
auto = new AMap.Autocomplete(autoOptions);
}};
```
### setType
设置提示Poi类型,多个类型用“|”分隔,POI相关类型请在网站“相关下载”处下载,目前只支持Poi类型编码如“050000” 默认值:所有类别
#### Parameters
- `type` **String** 提示Poi类型
### setCity
设置城市
#### Parameters
- `city` **String** 城市
### setCityLimit
设置是否强制限制城市
#### Parameters
- `citylimit` **boolean** 是否强制限制城市
### search
根据输入关键字提示匹配信息,支持中文、拼音
#### Parameters
- `keyword` **String** 关键字
- `callback` **AutoCompleteSearchCallback** 搜索结果回调
## AutoCompleteSearchCallback
搜索结果回调
Type: function
### Parameters
- `status` **string** 返回信息状态 可取值:'complete': result 为 AutocompleteResult; 'error': result为错误信息;'no_data': result 为 0
- `result` **searchResult** 返回结果详细信息
- `result.info` **string** 查询状态说明
- `result.count` **number** 输入提示条数
- `result.tips` **Array<Tip>** 输入提示列表
- `result.tips.name` **string** 名称
- `result.tips.district` **string** 所属区域
- `result.tips.adcode` **string** 区域编码
## PlaceSearch
地点搜索服务插件,提供某一特定地区的位置查询服务。
### Examples
```javascript
mapObj.plugin(['AMap.PlaceSearch'], function() {
var PlaceSearchOptions = { //设置PlaceSearch属性
city: "北京", //城市
type: "", //数据类别
pageSize: 10, //每页结果数,默认10
pageIndex: 1, //请求页码,默认1
extensions: "base" //返回信息详略,默认为base(基本信息)
};
var MSearch = new AMap.PlaceSearch(PlaceSearchOptions); //构造PlaceSearch类
AMap.event.addListener(MSearch, "complete", keywordSearch_CallBack); //返回结果
MSearch.search('方恒国际中心'); //关键字查询
});
```
### search
根据输入关键字提示匹配信息,支持中文、拼音
#### Parameters
- `keyword` **string** 关键字
- `callback` **searchCallback** 搜索结果回调
### searchInBounds
根据范围和关键词进行范围查询
#### Parameters
- `keyword` **string** 关键词
- `bounds` **AMap.Bounds** 范围
- `callback` **searchCallback** 搜索结果回调
### searchNearBy
根据中心点经纬度、半径以及关键字进行周边查询 radius取值范围:0-50000
#### Parameters
- `keyword` **string** 关键字
- `center` **AMap.LngLat** 中心点经纬度
- `radius` **number** 半径
### getDetails
根据PGUID 查询POI 详细信息
#### Parameters
- `PGUID` **string** PGUID
### setType
设置查询类别,多个类别用“|”分割
#### Parameters
- `type` **string** 类别
### setPageIndex
设置显示查询结果页码
#### Parameters
- `pageIndex` **number** 结果页码
### setPageSize
设置每页显示查询结果数量
#### Parameters
- `pageSize` **number** 页数
### setCity
设置查询城市, 支持cityname(中文或中文全拼)、citycode、adcode
#### Parameters
- `city` **string** 城市标识
### setCityLimit
设置是否强制限制城市
#### Parameters
- `citylimit` **boolean** 是否开启
### poiOnAMAP
唤起高德地图客户端marker页
Object 参数:{
id: "B000A7BD6C", POIID
name:String, 必要参数
location:LngLat|position属性 必须参数
}
例如:{
id: "B000A7BD6C",
location: LngLat,
name: "清华大学",
address: "地址"
}
#### Parameters
- `p`
- `opts` **object** 调起参数
### detailOnAMAP
唤起高德地图客户端POI详情页
Object 参数:{
id: "B000A7BD6C", POIID
name:String, 必要参数
location:LngLat|position属性 必须参数
}
#### Parameters
- `p`
- `opts` **object** 调起
## searchCallback
搜索结果回调
Type: function
### Parameters
- `status` **string** 返回信息状态 可取值:'complete': result 为 AutocompleteResult; 'error': result为错误信息;'no_data': result 为 0
- `result` **SearchResult** 返回结果详细信息
- `result.info` **string** 成功状态说明
- `result.keywordList` **Array<keyword>** 发生事件且查无此关键字时,返回建议关键字列表,可根据建议关键字查询
- `result.cityList` **Array<cityInfo>** 发生事件且查无此关键字且 city 为“全国”时,返回城市建议列表,该列表中每个城市包含一个或多个相关Poi点信息
- `result.cityList.name` **string** 建议城市名称
- `result.cityList.citycode` **string** 城市编码
- `result.cityList.adcode` **string** 行政区编码
- `result.cityList.count` **string** 该城市的建议结果数目
- `result.poiList` **object** 发生事件时返回兴趣点列表
- `result.poiList.pageIndex` **number** 页码
- `result.poiList.pageSize` **number** 单页结果数
- `result.poiList.count` **number** 查询结果总数
- `result.poiList.pois` **Array<POI>** Poi列表
- `result.poiList.pois.id` **string** 兴趣点id
- `result.poiList.pois.name` **string** 名称
- `result.poiList.pois.type` **string** 兴趣点类型
- `result.poiList.pois.location` **LngLat** 兴趣点经纬度
- `result.poiList.pois.address` **string** 地址
- `result.poiList.pois.distance` **number** 离中心点距离,仅周边查询返回
- `result.poiList.pois.tel` **string** 电话
- `result.poiList.pois.website` **string** 网址
- `result.poiList.pois.pcode` **string** poi所在省份编码
- `result.poiList.pois.citycode` **string** poi所在城市编码
- `result.poiList.pois.adcode` **string** poi所在区域编码
- `result.poiList.pois.postcode` **string** 邮编
- `result.poiList.pois.pname` **string** poi所在省份
- `result.poiList.pois.cityname` **string** poi所在城市名称
- `result.poiList.pois.adname` **string** poi所在行政区名称
- `result.poiList.pois.email` **string** 电子邮箱
- `result.poiList.pois.entr_location` **LngLat** 入口经纬度,POI点有出入口信息时返回,否则返回空字符串
- `result.poiList.pois.exit_location` **LngLat** 出口经纬度,POI点有出入口信息时返回,否则返回空字符串
## CloudDataSearch
云数据检索服务类
### Parameters
- `tableid` **string**
- `opts` **CloudDataSearchOptions**
- `opts.map` **Map** AMap.Map对象, 展现结果的地图实例。当指定此参数后,搜索结果的标注、线路等均会自动添加到此地图上。可选值
- `opts.keywords` **string** 云检索关键字,仅支持对建立了文本索引的字段进行模糊检索(请在[云数据管理平台][100]中管理文本索引)
- `opts.filter` **string** 云检索的筛选条件,仅支持对建立了排序筛选索引的字段进行筛选(请在云数据管理平台中管理排序筛选索引);支持多个筛选条件,支持对文本字段的精确匹配和对数值字段的区间筛选。筛选条件之间使用“+”代表“与”关系,如:filter:"\_name:酒店+star:[3,5]"(等同于SOL语句的:WHERE_name="酒店" AND star BETWEEN 3 AND 5)
- `opts.orderBy` **string** 返回数据的排序规则。1.支持系统预设排序规则:\_distance:坐标与中心点距离升序排序(仅对周边检索有效;)\_weight:权重降序排序。默认值:1)当设置了keywords时,默认按"\_weight"权重排序;2)当未设置keywords时,默认按"\_distance"距离排序。2.支持对建立了排序筛选索引的整数或小数字段进行排序(请在云数据管理平台中管理排序筛选索引)。升降序分别为"ASC"、"DESC",若仅填字段不填升降序则默认按升序排列,如:orderBy:"age:ASC"
- `opts.pageSize` **number** 单页显示结果数,取值范围[0-100],超过取值范围取默认值,默认:20
- `opts.pageIndex` **number** 当前页码,取值>=1,默认1
- `opts.panel` **(string \| HTMLElement)** 结果列表的HTML容器id或容器元素,提供此参数后,结果列表将在此容器中进行展示。可选值
- `opts.autoFitView` **boolean** 用于控制在搜索结束后,是否自动调整地图视野使绘制的Marker点都处于视口的可见范围
### Examples
```javascript
AMap.plugin('AMap.CloudDataSearch', function(){
var map = new AMap.Map("map", {
resizeEnable: true,
zoom: 12 //地图显示的缩放级别
});
var search, center = new AMap.LngLat(116.39946, 39.910829);
var searchOptions = {
map: map,
panel: 'panel',
keywords: '',
pageSize: 5,
orderBy: '_id:ASC'
};
search = new AMap.CloudDataSearch('532b9b3ee4b08ebff7d535b4', searchOptions);
search.searchNearBy(center, 1000);
});
```
### setOptions
设置云数据检索属性
#### Parameters
- `opts` **CloudDataSearchOptions**
### clear
清除搜索结果
### searchNearBy
周边检索,根据指定的中心点和半径检索位置数据。
#### Parameters
- `center` **LngLat** 搜索中心
- `radius` **number** 取值范围[0-50000],超过取值范围按3000,单位:米
- `callback` **CloudDataSearchCallback** 搜索回调
### searchById
根据数据id检索位置数据,id检索时不需要设置CloudDataSearchOptions
#### Parameters
- `id` **string**
- `callback` **CloudDataSearchCallback** 搜索回调
### searchByDistrict
根据行政区划(包括全国/省/市/区县)名称,检索行政区划内位置数据.
#### Parameters
- `district` **string** district为“全国”,则对全表搜索当district非法或不正确时,按照district为“全国”返回
- `callback` **CloudDataSearchCallback** 搜索回调
### searchInPolygon
多边形检索,根据给定的多边形节点坐标数组,检索位置数据。如果数组只有两个坐标元素,则认为多边形为矩形,这两个点为矩形的左下、右上点。多边形坐标数组的起、终点必须保证多边形闭合(起、终点坐标相同)
#### Parameters
- `path` **Array<LngLat>** 检索范围路径
- `callback` **CloudDataSearchCallback** 搜索回调
## CloudDataSearchCallback
搜索结果回调
Type: function
### Parameters
- `status` **string** 返回信息状态 可取值:'complete': result 为 AutocompleteResult; 'error': result为错误信息;'no_data': result 为 0
- `result` **object** 返回结果详细信息
- `result.info` **string** 成功状态文字描述
- `result.count` **number** 查询结果总数
- `result.datas` **Array<CloudData>** 云数据数组,当根据数据id检索时,数据仅包含一个CloudData
- `result._id` **string** 数据id,id为数据唯一标识
- `result._name` **string** 名称
- `result._location` **LngLat** 坐标
- `result._address` **string** 地址
- `result._updatetime` **string** 数据更新时间
- `result._distance` **number** 距离中心点距离(仅周边查询时返回)
- `result.custom_field1` **any** 用户自定义字段1
- `result._image` **Array<Image>** 图片信息
- `result._image._id` **string** 图片的id标识
- `result._image._preurl` **string** 经过压缩处理的图片地址,尺寸为400\*400,若期望获取体积较小的图片文件,建议使用此地址
- `result._image._url` **string** 最大限制获取1024\*1024,若您的原始图片小于该尺寸,将返回原图。
FILE:references/api/services-other.md
## 其他服务
行政区查询、天气查询、公交站点和公交线路查询
## DistrictSearch
**Extends AMap.Event**
行政区查询服务(AMap.DistrictSearch)提供行政区信息的查询,
使用该服务可以获取到行政区域的区号、城市编码、中心点、边界、下辖区域等详细信息,为基于行政区域的地图功能提供支持。
### Parameters
- `opts` **DistrictSearchOptions** 默认参数
- `level` **string** 关键字对应的行政区级别或商圈,可选值:
country:国家
province:省/直辖市
city:市
district:区/县
biz_area:商圈
- `showbiz` **boolean** 是否显示商圈,默认值true
可选为true/false,为了能够精准的定位到街道,特别是在快递、物流、送餐等场景下,强烈建议将此设置为false
- `extensions` **string** 是否返回行政区边界坐标点,默认值:base,不返回行政区边界坐标点,取值:all,返回完整行政区边界坐标点
- `subdistrict` **number** 显示下级行政区级数(行政区级别包括:国家、省/直辖市、市、区/县4个级别),商圈为区/县下一
级,可选值:0、1、2、3,默认值:1
0:不返回下级行政区
1:返回下一级行政区
2:返回下两级行政区
3:返回下三级行政区
### Examples
```javascript
AMap.plugin('AMap.DistrictSearch', function () {
var districtSearch = new AMap.DistrictSearch({
// 关键字对应的行政区级别,country表示国家
level: 'country',
// 显示下级行政区级数,1表示返回下一级行政区
subdistrict: 1
})
// 搜索所有省/直辖市信息
districtSearch.search('中国', function(status, result) {
// 查询成功时,result即为对应的行政区信息
})
})
// 除了获取所有省份/直辖市信息外,您可以通过修改level和subdistrict并配合search传入对应keyword查询对应信息。
```
### setLevel
设置关键字对应的行政区级别或商圈,可选值:
country:国家
province:省/直辖市
city:市
district:区/县
biz_area:商圈
#### Parameters
- `level` **string** 设置级别
### setSubdistrict
设置下级行政区级数(行政区级别包括:国家、省/直辖市、市、区/县4个级别),商圈为区/县下一级,默认值:1
可选值:0、1、2、3
0:不返回下级行政区;
1:返回下一级行政区;
2:返回下两级行政区;
3:返回下三级行政区;
#### Parameters
- `subdistrict` **string** 下级行政区级数
### search
根据关键字查询行政区或商圈信息 关键字支持:行政区名、citycode、adcode、商圈名。默认值:“全国”
当status为complete时,result为DistrictSearchResult;
当status为error时,result为错误信息info;
当status为no_data时,代表检索返回0结果
#### Parameters
- `keyword`
- `DistrictSearchCallBack` **function (status: String, result: info/DistrictSearchResult)** 回调函数
- `keywords` **string** 查询的关键字
## Weather
天气查询服务,根据城市名称或区域编码返回城市天气预报信息,包括实时天气信息和四天天气预报。
### Examples
```javascript
map.plugin(['AMap.Weather'], function() {
//构造 Weather 类
var amapWeather = new AMap.Weather();
//查询实时天气信息,cityName 见 http://restapi.amap.com/v3/config/district?level=city&sublevel=0&extensions=all&output=xml&key=d9fba2f3196b6a4419358693a2b0d9a9
amapWeather.getLive('北京');
//查询四天预报天气,包括查询当天天气信息
amapWeather.getForecast('北京');
AMap.event.addListener(amapWeather, "complete", function callback(){
//当查询成功时触发 complete 事件
});
});
```
### getLive
查询实时天气信息。
#### Parameters
- `city` **String** 城市名称/区域编码(如:“杭州市”/“330100”)
- `callback` **WeatherLiveResult** 回调函数
### getForecast
查询四天预报天气,包括查询当天天气信息
#### Parameters
- `city` **String**
- `callback` **WeatherForecastResult** 回调函数
## WeatherLiveResult
Type: Function
### Parameters
- `err` **Object** 正确时为空
- `LiveData` **Object** 返回数据
- `LiveData.info` **String** 成功状态文字描述
- `LiveData.province` **String** 省份名
- `LiveData.city` **String** 城市名
- `LiveData.adcode` **String** 区域编码
- `LiveData.weather` **String** 天气现象,详见天气现象列表
- `LiveData.temperature` **String** 实时气温,单位:摄氏度
- `LiveData.windDirection` **String** 风向,风向编码对应描述
- `LiveData.windPower` **Number** 风力,风力编码对应风力级别,单位:级
- `LiveData.humidity` **String** 空气湿度(百分比)
- `LiveData.reportTime` **String** 数据发布的时间
## WeatherForecastResult
Type: Function
### Parameters
- `err` **Object** 正确时为空
- `ForecastData` **Object** 返回数据
- `ForecastData.info` **String** 成功状态文字描述
- `ForecastData.province` **String** 省份名
- `ForecastData.city` **String** 城市名
- `ForecastData.adcode` **String** 区域编码
- `ForecastData.reportTime` **String** 数据发布的时间
- `ForecastData.forecast` **Array** 天气预报数组,包括当天至第三天的预报数据
- `ForecastData.forecast.date` **String** 日期,格式为“年-月-日”
- `ForecastData.forecast.week` **String** 星期
- `ForecastData.forecast.dayWeather` **String** 白天天气现象,详见天气现象列表
- `ForecastData.forecast.nightWeather` **String** 夜间天气现象,详见天气现象列表
- `ForecastData.forecast.dayTemp` **Number** 白天温度
- `ForecastData.forecast.nightTemp` **Number** 白天温度
- `ForecastData.forecast.dayWindDir` **String** 白天风向
- `ForecastData.forecast.dayWindPower` **String** 白天风力
- `ForecastData.forecast.nightWindPower` **String** 夜间风力
## StationSearch
**Extends AMap.Event**
AMap.StationSearch 公交站点查询服务,根据输入关键字、ID查询公交站点信息。
用户可以通过自定义回调函数取回并显示查询结果。若服务请求失败,系统将返回错误信息。
### Parameters
- `opts` **StationSearchOptions** 参数信息
- `opts.pageIndex` **Number** 页码(如pageIndex为2,pageSize为10,那么显示的应是第11-20条返回结果)
默认值:1,取值范围:1-100,超过取值范围按默认,超出实际页数按最大值返回
- `opts.pageSize` **Number** 单页显示结果条数,默认值:20,取值范围:1-100,超过取值范围按默认
- `opts.city` **String** 公交站点所在城市,默认值:“全国”,可选值:cityname(中文或中文全拼)、citycode、adcode
### Examples
```javascript
//加载公交站点查询插件
mapObj.plugin(["AMap.StationSearch"], function() {
//实例化公交站点查询类
var station = new AMap.StationSearch({
pageIndex: 1, //页码
pageSize: 10, //单页显示结果条数
city:'010' //确定搜索城市
});
station.search('东直门'); //查询
AMap.event.addListener(station, 'complete', stationSearch_CallBack);
AMap.event.addListener(station, 'error', function(e) {alert(e.info);});
});
```
### setPageIndex
设置查询结果页码,默认值:1 取值范围:1-100,超过取值范围按默认
#### Parameters
- `pageIndex` **Number** 结果页码
### setPageSize
设置单页显示结果条数,默认值:20 取值范围:1-100,超过取值范围按默认
#### Parameters
- `pageSize` **Number** 单页显示结果条数
### setCity
设置查询城市,默认值:“全国” 可选值:cityname(中文或中文全拼)、citycode、adcode
#### Parameters
- `city` **String** 查询城市
### setCity
根据给定的公交站点id进行公交站点详情检索,id是公交站点的唯一标识
当status为complete时,result为StationSearchResult;
当status为error时,result为错误信息info;
当status为no_data时,代表检索返回0结果
#### Parameters
- `id` **String** 公交站点 id
### setCity
根据给定公交站点名称进行公交站点详情查询,多个关键字用"|"分割,status说明同上 [相关示例][134]
#### Parameters
- `keyword` **String** 公交站点名称
- `StationSearchCallback` **String** 回调函数
### StationSearchOptions
Type: Object
#### Properties
- `pageIndex` **Number** 页码(如pageIndex为2,pageSize为10,那么显示的应是第11-20条返回结果),默认值:1 取值范围:1-100,超过取值范围按默认; 超出实际页数,按最大值
- `pageSize` **Number** 单页显示结果条数,默认值:20
- `city` **String** 公交线路所在城市
## LineSearch
**Extends AMap.Event**
AMap.LineSearch 公交路线查询类,通过extensions属性控制返回信息详略。
公交线路信息包括起、终点、途径站点,首、末班车时间等信息。用户可以通过自定义回调函数取回并显示查询结果。
若服务请求失败,系统将返回[错误信息][135]。
### Parameters
- `opts` **LineSearchOptions** 参数信息
- `opts.pageIndex` **Number** 页码(如pageIndex为2,pageSize为10,那么显示的应是第11-20条返回结果)
默认值:1,取值范围:1-100,超过取值范围按默认,超出实际页数按最大值返回
- `opts.pageSize` **Number** 单页显示结果条数,默认值:20,取值范围:1-100,超过取值范围按默认
- `opts.city` **String** 公交站点所在城市,默认值:“全国”,可选值:cityname(中文或中文全拼)、citycode、adcode
- `extensions` **String** 此项仅公交路线查询时有效,默认值:base,返回公交路线基本信息,当取值为:all,返回公交路线基本信息+详细信息
### Examples
```javascript
//加载公交线路查询插件
mapObj.plugin(["AMap.LineSearch"], function() {
//实例化公交线路查询类
var linesearch = new AMap.LineSearch({
pageIndex:1,
pageSize:1,
extensions:'all'
});
//搜索“536”相关公交线路
linesearch.search('536');
AMap.event.addListener(linesearch, "complete", lineSearch_Callback);
AMap.event.addListener(citysearch, "error", function(e){alert(e.info);});
});
```
### setPageIndex
设置查询结果页码,默认值:1 取值范围:1-100,超过取值范围按默认
#### Parameters
- `pageIndex` **Number** 结果页码
### setPageSize
设置单页显示结果条数,默认值:20 取值范围:1-100,超过取值范围按默认
#### Parameters
- `pageSize` **Number** 单页显示结果条数
### setCity
设置查询城市,默认值:“全国” 可选值:cityname(中文或中文全拼)、citycode、adcode
#### Parameters
- `city` **String** 城市
### setCity
设置查询城市,默认值:“全国” 可选值:cityname(中文或中文全拼)、citycode、adcode
#### Parameters
- `city` **String** 查询城市
### setCity
根据给定的公交站点id进行公交站点详情检索,id是公交站点的唯一标识
当status为complete时,result为LineSearchResult;
当status为error时,result为错误信息info;
当status为no_data时,代表检索返回0结果
#### Parameters
- `id` **String** 公交站点 id
### setCity
根据给定公交站点名称进行公交站点详情查询,多个关键字用"|"分割,status说明同上 [相关示例][136]
#### Parameters
- `keyword` **String** 公交站点名称
- `LineSearchCallback` **String** 回调函数
### LineSearchOptions
Type: Object
#### Properties
- `pageIndex` **Number** 页码(如pageIndex为2,pageSize为10,那么显示的应是第11-20条返回结果),默认值:1 取值范围:1-100,超过取值范围按默认; 超出实际页数,按最大值
- `pageSize` **Number** 单页显示结果条数,默认值:20
- `city` **String** 公交线路所在城市
- `extensions` **String** 此项仅公交路线查询时有效 默认值:base,返回公交路线基本信息 当取值为:all,返回公交路线基本信息+详细信息
FILE:references/api/services.md
## 服务类
用于调用 Web 服务 API,直接透传查询条件和返回结果
## WebService
用于调用 Web 服务 API,直接透传查询条件和返回结果,提供GET和POST两种请求方式,具体请求接口和返回结果,请参考 [https://lbs.amap.com/api/webservice/summary/][96]
### get
以 GET 请求方式请求指定的 Web 服务 API 接口
#### Parameters
- `path` **string** Web服务API的接口路径
- `params` **object** Web服务 API 的查询参数
- `callback` **WebServiceCallback** 查询回调函数
- `opts` **HttpOptions** HTTP 请求参数配置 (optional, default `{}`)
#### Examples
```javascript
AMap.WebService.get('https://restapi.amap.com/v3/place/text',
{
keywords : '首开广场',
types : '写字楼',
city : '010'
},function (error, result) {
console.log(error, result);
}
);
```
### post
以 POST 请求方式请求指定的 Web 服务 API 接口, 目前只有轨迹纠偏接口需要使用 POST 方式
#### Parameters
- `path` **string** Web服务API的接口路径
- `params` **any** Web服务 API 的查询参数
- `callback` **WebServiceCallback** 查询回调函数
#### Examples
```javascript
AMap.WebService.post('https://restapi.amap.com/v4/grasproad/driving',
[
{"x":116.478928,"y":39.997761,"sp":19,"ag":0, "tm":1478031031},
{"x":116.478907,"y":39.998422,"sp":10,"ag":0, "tm":2},
{"x":116.479384,"y":39.998546,"sp":10,"ag":110,"tm":3},
{"x":116.481053,"y":39.998204,"sp":10,"ag":120,"tm":4},
{"x":116.481793,"y":39.997868,"sp":10,"ag":120,"tm":5}
],function (error, result) {
console.log(error, result);
}
);
```
## WebServiceCallback
WebService 的回调函数类型
Type: Function
### Parameters
- `status` **string** 服务查询的状态结果,'complete' 或 'error'
- `data` **any** Web服务API返回的数据
FILE:references/api/tools.md
## 工具类
用于满足一定专门功能的工具类型
## RangingTool
构造一个距离量测插件对象。参数map为地图实例。 opts属性参考RangingToolOptions列表中的说明
### Parameters
- `map` **Map** 要添加到的地图实例
- `opts` **RangingToolOptions** 鼠标工具配置参数
- `opts.startMarkerOptions` **Object** 设置量测起始点标记属性对象,包括点标记样式、大小等,参考 MarkerOptions
- `opts.midMarkerOptions` **Object** 设置量测中间点标记属性对象,包括点标记样式、大小等,参考 MarkerOptions
- `opts.endMarkerOptions` **Object** 设置量测结束点标记属性对象,包括点标记样式、大小等,参考 MarkerOptions
- `opts.lineOptions` **Object** 设置距离量测线的属性对象,包括线样式、颜色等,参考 PolylineOptions
- `opts.tmpLineOptions` **Object** 设置距离量测过程中临时量测线的属性对象,包括线样式、颜色,参考 PolylineOptions
- `opts.startLabelText` **String** 设置量测起始点标签的文字内容,默认为“起点”
- `opts.midLabelText` **String** 设置量测中间点处标签的文字内容,默认为当前量测结果值
- `opts.endLabelText` **String** 设置量测结束点处标签的文字内容,默认为当前量测结果值
- `opts.startLabelOffset` **Pixel** 设置量测起始点标签的偏移量。默认值:Pixel(-6, 6)
- `opts.midLabelOffset` **Pixel** 设置量测中间点标签的偏移量。默认值:Pixel(-6, 6)
- `opts.endLabelOffset` **Pixel** 设置量测结束点标签的偏移量。默认值:Pixel(-6, 6)
### Examples
```javascript
map.plugin(["AMap.MouseTool"],function(){
var ruler = new AMap.RangingTool(map);
});
```
### turnOn
启动测距工具
### turnOff
关闭测距工具
#### Parameters
- `removeOverlays` **Boolean** 是否删除测距过程产生的覆盖物
## MouseTool
鼠标工具插件。通过该插件,可进行鼠标画标记点、线、多边形、矩形、圆、距离量测、面积量测、拉框放大、拉框缩小等功能。
### Parameters
- `map` **Map** 鼠标工具添加到的地图实例
### Examples
```javascript
map.plugin(["AMap.MouseTool"],function(){
var mousetool = new AMap.MouseTool(map);
// 使用鼠标工具,在地图上画标记点
mousetool.marker();
});
```
### marker
开启鼠标画点标注模式。鼠标在地图上单击绘制点标注,标注样式参考MarkerOptions设置
#### Parameters
- `opts` **MarkerOptions** 参考MarkerOptions设置
### circle
开启鼠标画圆模式。鼠标在地图上拖动绘制相应的圆形。圆形样式参考CircleOptions设置
#### Parameters
- `opts` **CircleOptions** 参考CircleOptions设置
### rectangle
开启鼠标画矩形模式。鼠标在地图上拉框即可绘制相应的矩形。矩形样式参考PolygonOptions设置
#### Parameters
- `opts` **PolygonOptions** 矩形样式参考PolygonOptions设置
### polyline
开启鼠标画折线模式。鼠标在地图上点击绘制折线,鼠标左键双击或右键单击结束绘制,折线样式参考PolylineOptions设置
#### Parameters
- `opts` **PolylineOptions** 参考PolylineOptions设置
### polygon
开启鼠标画多边形模式。鼠标在地图上单击开始绘制多边形,鼠标左键双击或右键单击结束当前多边形的绘制,多边形样式参考PolygonOptions设置
#### Parameters
- `opts` **PolygonOptions** 参考PolygonOptions设置
### measureArea
开启面积量测模式。鼠标在地图上单击绘制量测区域,鼠标左键双击或右键单击结束当前量测操作,并显示本次量测结果。量测面样式参考PolygonOptions设置
#### Parameters
- `opts` **PolygonOptions** 参考PolygonOptions设置
### rule
开启距离量测模式。鼠标在地图上单击绘制量测节点,并计算显示两两节点之间的距离,鼠标左键双击或右键单击结束当前量测操作。量测线样式参考 PolylineOptions 设置
注:不能同时使用rule方法和RangTool插件进行距离量测
#### Parameters
- `opts` **PolylineOptions** 参考PolylineOptions设置
### rectZoomIn
开启鼠标拉框放大模式。鼠标可在地图上拉框放大地图。矩形框样式参考PolygonOptions设置
#### Parameters
- `opts` **PolygonOptions** 参考PolygonOptions设置
### rectZoomOut
开启鼠标拉框缩小模式。鼠标可在地图上拉框缩小地图。矩形框样式参考PolygonOptions设置
#### Parameters
- `opts` **PolygonOptions** 参考PolygonOptions设置
### close
关闭当前鼠标操作。参数arg设为true时,鼠标操作关闭的同时清除地图上绘制的所有覆盖物对象;设为false时,保留所绘制的覆盖物对象。默认为false
#### Parameters
- `ifClear` **boolean** 是否清除地图上的覆盖物
## PolygonEditor
Polygon 编辑器
### Parameters
- `map` **Map** AMap.Map 的实例
- `polygon` **Polygon?** 编辑对象
- `opts` **Object?** 设置参数
- `opts.createOptions` **Object?** 新创建的对象样式
- `opts.editOptions` **Object?** 编辑样式
- `opts.controlPoint` **Object?** 顶点样式 CircleMarkerOptions
- `opts.midControlPoint` **Object?** 中间点样式 CircleMarkerOptions
### open
开始编辑对象
### setTarget
设置编辑对象
#### Parameters
- `tar`
- `overlay` **Polygon**
### getTarget
获取编辑对象
Returns **(Polygon \| undefined)**
### setAdsorbPolygons
设置吸附多边形
#### Parameters
- `list` **(Polygon \| Array<Polygon>)**
### clearAdsorbPolygons
清空所有的吸附多边形
### addAdsorbPolygons
添加吸附多边形
#### Parameters
- `list` **(Polygon \| Array<Polygon>)**
### removeAdsorbPolygons
删除吸附多边形
#### Parameters
- `list` **(Polygon \| Array<Polygon>)**
### close
停止编辑对象
## PolylineEditor
折线编辑插件,用于编辑AMap.Polyline对象,支持通过鼠标调整折线的形状。
### Parameters
- `map` **Map** AMap.Map 的实例
- `polygon` **Polygon?** 编辑对象
- `opts` **Object?** 设置参数
- `opts.createOptions` **Object?** 新创建的对象样式
- `opts.editOptions` **Object?** 编辑样式
- `opts.controlPoint` **Object?** 顶点样式 CircleMarkerOptions
- `opts.midControlPoint` **Object?** 中间点样式 CircleMarkerOptions
### setTarget
设置编辑对象
#### Parameters
- `overlay` **Polyline?**
### getTarget
获取编辑对象
Returns **(Polyline \| undefined)** 当前编辑对象
### open
开始编辑对象
### close
停止编辑对象
## CircleEditor
圆编辑插件。用于编辑AMap.Circle对象,功能包括使用鼠标改变圆半径大小、拖拽圆心改变圆的位置。
### Parameters
- `map` **Map** AMap.Map 实例
- `circle` **Circle?** 可选参数, AMap.Circle 实例
- `opts` **Object?** 设置参数
- `opts.createOptions` **Object?** 新创建的对象样式
- `opts.editOptions` **Object?** 编辑样式
- `opts.movePoint` **Object?** 移动点样式 MarkerOptions
- `opts.resizePoint` **Object?** reaize点样式 MarkerOptions
### setTarget
设置编辑对象
#### Parameters
- `overlay` **Circle?** 编辑对象
### getTarget
获取编辑对象
Returns **(Circle \| undefined)** 当前编辑对象
### open
打开编辑功能
### close
关闭编辑功能
## BezierCurveEditor
贝塞尔曲线编辑器
### Parameters
- `map` **Map** AMap.Map 实例
- `bezier` **BezierCurve?** 曲线示例
- `opts` **Object?** 设置参数
- `opts.createOptions` **Object?** 新创建的对象样式
- `opts.editOptions` **Object?** 编辑样式
- `opts.controlPoint` **Object?** 顶点样式 MarkerOptions
- `opts.midControlPoint` **Object?** 中间点样式 MarkerOptions
- `opts.bezierControlPoint` **Object?** 贝塞尔控制点样式MarkerOptions
- `opts.bezierControlLine` **Object?** 贝塞尔控制线样式PolylineOptions
### setTarget
设置编辑对象
#### Parameters
- `overlay` **BezierCurve?**
### getTarget
获取编辑对象
Returns **(BezierCurve \| undefined)** [overlay] 当前编辑对象
### open
开始编辑对象
### close
结束编辑对象
## EllipseEditor
椭圆编辑器
### Parameters
- `map` **Map** AMap.Map 的实例
- `ellipse` **Ellipse?** AMap.Ellipse 的实例
- `opts` **Object?** 设置参数
- `opts.createOptions` **Object?** 新创建的对象样式
- `opts.editOptions` **Object?** 编辑样式
- `opts.movePoint` **Object?** 移动点样式 MarkerOptions
- `opts.resizeXPoint` **Object?** reaizeX点样式 MarkerOptions
- `opts.resizeYPoint` **Object?** reaizeY点样式 MarkerOptions
### setTarget
设置编辑对象
#### Parameters
- `overlay` **Ellipse?** 编辑对象
### getTarget
获取编辑对象
Returns **(Ellipse \| undefined)** 当前编辑对象
### open
打开编辑功能
### close
关闭编辑功能
## RectangleEditor
矩形编辑器
### Parameters
- `map` **Map** AMap.Map 的实例
- `rect` **Rectangle?** AMap.Rectangle 的实例
- `opts` **Object?** 设置参数
- `opts.createOptions` **Object?** 新创建的对象样式
- `opts.editOptions` **Object?** 编辑样式
- `opts.southWestPoint` **Object?** 西南点样式 MarkerOptions
- `opts.northEastPoint` **Object?** 东北点样式 MarkerOptions
### setTarget
设置编辑对象
#### Parameters
- `overlay` **Rectangle?** 编辑对象
### getTarget
获取编辑对象
Returns **(Rectangle \| undefined)** 当前编辑对象
### open
打开编辑功能
### close
关闭编辑功能
FILE:references/api/vector-graphics.md
## 矢量图形
用于在地图上绘制线、面等矢量地图要素的类型
## Polygon
构造多边形对象,通过PolygonOptions指定多边形样式
### Parameters
- `opts` **PolygonOptions**
- `opts.path` **(Array<LngLat> | Array<Array<LngLat>> | Array<Array<Array<LngLat>>>)** 多边形轮廓线的节点坐标数组。
支持 单个普通多边形({Array<LngLat>}),单个带孔多边形({Array<Array<LngLat>>}),多个带孔多边形({Array<Array<Array<LngLat>>>})
- `opts.zIndex` **number** 多边形覆盖物的叠加顺序。地图上存在多个多边形覆盖物叠加时,通过该属性使级别较高的多边形覆盖物在上层显示 (optional, default `10`)
- `opts.bubble` **boolean** 是否将覆盖物的鼠标或touch等事件冒泡到地图上(自v1.3 新增) (optional, default `false`)
- `opts.cursor` **string?** 指定鼠标悬停时的鼠标样式,自定义cursor,IE仅支持cur/ani/ico格式,Opera不支持自定义cursor
- `opts.strokeColor` **string** 线条颜色,使用16进制颜色代码赋值。默认值为#00D3FC (optional, default `#00D3FC`)
- `opts.strokeOpacity` **number** 轮廓线透明度,取值范围[0,1],0表示完全透明,1表示不透明。默认为0.9 (optional, default `0.9`)
- `opts.strokeWeight` **number** 轮廓线宽度 (optional, default `2`)
- `opts.fillColor` **string** 多边形填充颜色,使用16进制颜色代码赋值,如:#00B2D5 (optional, default `#00B2D5`)
- `opts.fillOpacity` **number** 多边形填充透明度,取值范围[0,1],0表示完全透明,1表示不透明。默认为0.5 (optional, default `0.5`)
- `opts.draggable` **boolean** 设置多边形是否可拖拽移动,默认为false (optional, default `false`)
- `opts.extrusionHeight` **number** 设置多边形是否拉伸为的多面体厚度值。默认值为0 (optional, default `0`)
- `opts.wallColor` **(Array<String> | String)** 多面体侧面颜色,支持 rgba、rgb、十六进制等。默认为#00D3FC (optional, default `#00D3FC`)
- `opts.roofColor` **(Array<String> | String)** 多面体顶面颜色,支持 rgba、rgb、十六进制等。默认为#00B2D5 (optional, default `#00B2D5`)
- `opts.extData` **object?** 用户自定义属性,支持JavaScript API任意数据类型,如Polygon的id等。
- `opts.strokeStyle` **(`"solid"` \| `"dashed"`)** 轮廓线样式,实线:solid,虚线:dashed (optional, default `solid`)
- `opts.strokeDasharray` **Array<number>?** 勾勒形状轮廓的虚线和间隙的样式,此属性在strokeStyle 为dashed 时有效, 此属性在ie9+浏览器有效 取值:
实线:[0,0,0]
虚线:[10,10] ,[10,10] 表示10个像素的实线和10个像素的空白(如此反复)组成的虚线
点画线:[10,2,10], [10,2,10] 表示10个像素的实线和2个像素的空白 + 10个像素的实线和10个像素的空白 (如此反复)组成的虚线
### hide
隐藏多边形
### show
显示多边形
### getExtData
获取用户自定义属性
Returns **Object**
### setExtData
设置用户自定义属性,支持JavaScript API任意数据类型
#### Parameters
- `extData` **Object**
### getOptions
获取多边形的属性
Returns **Object** [多边形配置][84]
### setOptions
修改多边形属性(样式风格,包括组成多边形轮廓线的节点、轮廓线样式等。属性详情参看PolygonOptions列表)
#### Parameters
- `optsArg` **PolygonOptions**
### getPath
获取多边形轮廓线节点数组。
Returns **(Array<LngLat> | Array<Array<LngLat>> | Array<Array<Array<LngLat>>>)** 返回路径
### setExtrusionHeight
设置多面体拉伸高度值
### getExtrusionHeight
获取多边形当前拉伸高度值
Returns **number** 返回路径
### getBounds
获取当前多边形的矩形范围对象。
Returns **Bounds**
### getArea
获取多边形的面积(单位:平方米)
Returns **number**
### destroy
销毁内存-多边形
### contains
判断坐标是否在多边形内
#### Parameters
- `originPoint` **LngLatLike**
Returns **boolean** true 包含,false 不包含
### setPath
多边形轮廓线的节点坐标数组。支持 单个普通多边形({Array<LngLat>}),单个带孔多边形({Array<Array<LngLat>>}),多个带孔多边形({Array<Array<Array<LngLat>>>})
#### Parameters
- `path` **(Array<LngLatLike> | Array<Array<LngLatLike>> | Array<Array<Array<LngLatLike>>>)?**
### generateBuffer
#### Parameters
- `gl`
### getStatus
获取折线绘制状态的时间点
Returns **any**
## Polyline
构造折线对象,支持 lineString 和 MultiLineString
### Parameters
- `opts` {PolylineOptions}
- `opts.path` **(Array<LngLat> | Array<Array<LngLat>>)** polyline 路径,支持 lineString 和 MultiLineString
- `opts.zIndex` **number** 多边形覆盖物的叠加顺序。地图上存在多个多边形覆盖物叠加时,通过该属性使级别较高的多边形覆盖物在上层显示 (optional, default `10`)
- `opts.bubble` **boolean** 是否将覆盖物的鼠标或touch等事件冒泡到地图上(自v1.3 新增) (optional, default `false`)
- `opts.cursor` **string?** 指定鼠标悬停时的鼠标样式,自定义cursor,IE仅支持cur/ani/ico格式,Opera不支持自定义cursor
- `opts.strokeColor` **string** 线条颜色,使用16进制颜色代码赋值。默认值为#00D3FC (optional, default `#00D3FC`)
- `opts.strokeOpacity` **number** 轮廓线透明度,取值范围[0,1],0表示完全透明,1表示不透明。默认为0.5 (optional, default `0.5`)
- `opts.strokeWeight` **number** 轮廓线宽度 (optional, default `2`)
- `opts.borderWeight` **number** 描边线宽度 (optional, default `2`)
- `opts.isOutline` **boolean** 是否显示描边,默认false (optional, default `false`)
- `opts.borderWeight` **number** 描边的宽度,默认为1 (optional, default `1`)
- `opts.outlineColor` **string** 线条描边颜色,此项仅在isOutline为true时有效,默认:#00B2D5 (optional, default `#00B2D5`)
- `opts.draggable` **boolean** 设置多边形是否可拖拽移动,默认为false (optional, default `false`)
- `opts.extData` **object?** 用户自定义属性,支持JavaScript API任意数据类型,如Polygon的id等
- `opts.strokeStyle` **(`"solid"` \| `"dashed"`)** 轮廓线样式,实线:solid,虚线:dashed (optional, default `solid`)
- `opts.strokeDasharray` **Array<number>?** 勾勒形状轮廓的虚线和间隙的样式,此属性在strokeStyle 为dashed 时有效, 此属性在ie9+浏览器有效 取值:
实线:[0,0,0]
虚线:[10,10] ,[10,10] 表示10个像素的实线和10个像素的空白(如此反复)组成的虚线
点画线:[10,2,10], [10,2,10] 表示10个像素的实线和2个像素的空白 + 10个像素的实线和10个像素的空白 (如此反复)组成的虚线
- `opts.lineJoin` **(`"miter"` \| `"round"` \| `"bevel"`)** 折线拐点的绘制样式,默认值为'miter'尖角,其他可选值:'round'圆角、'bevel'斜角 (optional, default `miter`)
- `opts.lineCap` **(`"butt"` \| `"round"` \| `"square"`)** 折线两端线帽的绘制样式,默认值为'butt'无头,其他可选值:'round'圆头、'square'方头 (optional, default `butt`)
- `opts.geodesic` **boolean** 是否绘制成大地线,默认false (optional, default `false`)
- `opts.showDir` **boolean** 是否延路径显示白色方向箭头,默认false。建议折线宽度大于6时使用- @param {boolean} [opts.animate=false] 是否使用纹理动画,开启后,如果线有纹理,将会有流动动画
- @param {boolean} [opts.speed=100] 纹理流动动画的速度,单位 m/s (optional, default `false`)
### hide
隐藏折线
### show
显示折线
### getExtData
获取用户自定义属性
Returns **Object**
### getOptions
获取线的属性
Returns **PolylineOptions**
### getPath
获取折线路径的节点数组。
Returns **(Array<LngLat> | Array<Array<LngLat>>)**
### setExtData
设置用户自定义属性,支持JavaScript API任意数据类型
#### Parameters
- `extData` **Object**
### destroy
销毁内存-折线
### getBounds
获取当前折线的矩形范围对象
Returns **(Bounds \| undefined)**
### setPath
设置组成该折线的节点数组,支持单条折线(LngLatLike\[]) 多条折线(LngLatLike[][])
#### Parameters
- `path` **(Array<LngLatLike> | Array<Array<LngLatLike>>)?**
Returns **any**
### moveWithPos
#### Parameters
- `dx`
- `dy`
### getLength
获取折线的总长度(单位:米)
Returns **number**
### getEndDistance
### generateBuffer
#### Parameters
- `gl`
### setOptions
修改折线属性(包括路径的节点、线样式、是否绘制大地线等。属性详情参看PolylineOptions列表)
#### Parameters
- `optsArg` **PolylineOptions**
### contains
判断坐标是否在折线内
#### Parameters
- `point` **LngLatLike**
Returns **boolean**
### getStatus
获取折线绘制状态的时间点
Returns **any**
## BezierCurve
**Extends \_Polyline.CombinePolyline**
### Parameters
- `opts` (optional, default `{}`)
### setOptions
修改折线属性(包括路径的节点、线样式、是否绘制大地线等。属性详情参看 BezierCurveOptions 列表)
#### Parameters
- `optsArg` **BezierCurveOptions**
### generateBuffer
#### Parameters
- `gl`
### getPath
获取贝塞尔曲线路径的节点数组
Returns **(Array<Array<number>> | Array<Array<Array<number>>>)**
### setPath
设置组成该折线的节点数组
#### Parameters
- `path` **(Array<Array<number>> | Array<Array<Array<number>>>)** 贝瑟尔曲线的路径。描述为一个二维数组规则如下:第一个元素是起点,
之后的元素同时描述控制点和途经点,之后每个元素可以有0个到2个控制点
控制点在前,途经点在最后
\[
[lng,lat],//起点0
[lng,lat,lng,lat,lng,lat],//控制点、控制点、途经点2
[lng,lat,lng,lat]//控制点、途经点3
]
或者
\[
\[ [lng,lat] ],//起点0
\[ [lng,lat] , [lng,lat] ],//控制点、途经点1
\[ [lng,lat] , [lng,lat] , [lng,lat]],//控制点、控制点、途经点2
\[ [lng,lat] , [lng,lat] ]//控制点、途经点3
]
### getBounds
获取当前折线的矩形范围对象
Returns **(Bounds \| undefined)**
### getBounds
获取当前折线的矩形范围对象
Returns **(Bounds \| undefined)** Bounds对象,未设置路径时为 undefined
### hide
隐藏贝塞尔线
### show
显示贝塞尔曲线
### getExtData
获取用户自定义属性
Returns **Object**
### setExtData
设置用户自定义属性,支持JavaScript API任意数据类型
#### Parameters
- `extData` **Object**
### destroy
销毁内存-贝塞尔曲线
### getOptions
获取线的属性
Returns **BezierCurveOptions**
### contains
判断坐标是否在曲线内
#### Parameters
- `point` **LngLatLike**
Returns **boolean**
### getLength
获取曲线的总长度(单位:米)
Returns **number**
## BezierCurve
贝塞尔曲线
### Parameters
- `opts` **BezierCurveOptions** BezierCurve配置项
- `opts.path` **Array** 贝瑟尔曲线的路径。描述为一个二维数组规则如下:第一个元素是起点,
之后的元素同时描述控制点和途经点,之后每个元素可以有0个到2个控制点
控制点在前,途经点在最后
\[
[lng,lat],//起点0
[lng,lat,lng,lat,lng,lat],//控制点、控制点、途经点2
[lng,lat,lng,lat]//控制点、途经点3
]
或者
\[
\[ [lng,lat] ],//起点0
\[ [lng,lat] , [lng,lat] ],//控制点、途经点1
\[ [lng,lat] , [lng,lat] , [lng,lat]],//控制点、控制点、途经点2
\[ [lng,lat] , [lng,lat] ]//控制点、途经点3
]
- `opts.path` **(Array<LngLat> | Array<Array<LngLat>>)** polyline 路径,支持 lineString 和 MultiLineString
- `opts.zIndex` **number** 多边形覆盖物的叠加顺序。地图上存在多个多边形覆盖物叠加时,通过该属性使级别较高的多边形覆盖物在上层显示 (optional, default `10`)
- `opts.bubble` **boolean** 是否将覆盖物的鼠标或touch等事件冒泡到地图上(自v1.3 新增) (optional, default `false`)
- `opts.cursor` **string?** 指定鼠标悬停时的鼠标样式,自定义cursor,IE仅支持cur/ani/ico格式,Opera不支持自定义cursor
- `opts.strokeColor` **string** 线条颜色,使用16进制颜色代码赋值。默认值为#00D3FC (optional, default `#00D3FC`)
- `opts.strokeOpacity` **number** 轮廓线透明度,取值范围[0,1],0表示完全透明,1表示不透明。默认为0.5 (optional, default `0.5`)
- `opts.strokeWeight` **number** 轮廓线宽度 (optional, default `2`)
- `opts.borderWeight` **number** 描边线宽度 (optional, default `2`)
- `opts.isOutline` **boolean** 是否显示描边,默认false (optional, default `false`)
- `opts.borderWeight` **number** 描边的宽度,默认为1 (optional, default `1`)
- `opts.outlineColor` **string** 线条描边颜色,此项仅在isOutline为true时有效,默认:#00B2D5 (optional, default `#00B2D5`)
- `opts.draggable` **boolean** 设置多边形是否可拖拽移动,默认为false (optional, default `false`)
- `opts.extData` **object?** 用户自定义属性,支持JavaScript API任意数据类型,如Polygon的id等
- `opts.strokeStyle` **(`"solid"` \| `"dashed"`)** 轮廓线样式,实线:solid,虚线:dashed (optional, default `solid`)
- `opts.strokeDasharray` **Array<number>?** 勾勒形状轮廓的虚线和间隙的样式,此属性在strokeStyle 为dashed 时有效, 此属性在ie9+浏览器有效 取值:
实线:[0,0,0]
虚线:[10,10] ,[10,10] 表示10个像素的实线和10个像素的空白(如此反复)组成的虚线
点画线:[10,2,10], [10,2,10] 表示10个像素的实线和2个像素的空白 + 10个像素的实线和10个像素的空白 (如此反复)组成的虚线
- `opts.lineJoin` **(`"miter"` \| `"round"` \| `"bevel"`)** 折线拐点的绘制样式,默认值为'miter'尖角,其他可选值:'round'圆角、'bevel'斜角 (optional, default `miter`)
- `opts.lineCap` **(`"butt"` \| `"round"` \| `"square"`)** 折线两端线帽的绘制样式,默认值为'butt'无头,其他可选值:'round'圆头、'square'方头 (optional, default `butt`)
- `opts.geodesic` **boolean** 是否绘制成大地线,默认false (optional, default `false`)
- `opts.showDir` **boolean** 是否延路径显示白色方向箭头,默认false。建议折线宽度大于6时使用 (optional, default `false`)
### setOptions
修改折线属性(包括路径的节点、线样式、是否绘制大地线等。属性详情参看 BezierCurveOptions 列表)
#### Parameters
- `optsArg` **BezierCurveOptions**
### generateBuffer
#### Parameters
- `gl`
### getPath
获取贝塞尔曲线路径的节点数组
Returns **(Array<Array<number>> | Array<Array<Array<number>>>)**
### setPath
设置组成该折线的节点数组
#### Parameters
- `path` **(Array<Array<number>> | Array<Array<Array<number>>>)** 贝瑟尔曲线的路径。描述为一个二维数组规则如下:第一个元素是起点,
之后的元素同时描述控制点和途经点,之后每个元素可以有0个到2个控制点
控制点在前,途经点在最后
\[
[lng,lat],//起点0
[lng,lat,lng,lat,lng,lat],//控制点、控制点、途经点2
[lng,lat,lng,lat]//控制点、途经点3
]
或者
\[
\[ [lng,lat] ],//起点0
\[ [lng,lat] , [lng,lat] ],//控制点、途经点1
\[ [lng,lat] , [lng,lat] , [lng,lat]],//控制点、控制点、途经点2
\[ [lng,lat] , [lng,lat] ]//控制点、途经点3
]
### getBounds
获取当前折线的矩形范围对象
Returns **(Bounds \| undefined)**
### getBounds
获取当前折线的矩形范围对象
Returns **(Bounds \| undefined)** Bounds对象,未设置路径时为 undefined
### hide
隐藏贝塞尔线
### show
显示贝塞尔曲线
### getExtData
获取用户自定义属性
Returns **Object**
### setExtData
设置用户自定义属性,支持JavaScript API任意数据类型
#### Parameters
- `extData` **Object**
### destroy
销毁内存-贝塞尔曲线
### getOptions
获取线的属性
Returns **BezierCurveOptions**
### contains
判断坐标是否在曲线内
#### Parameters
- `point` **LngLatLike**
Returns **boolean**
### getLength
获取曲线的总长度(单位:米)
Returns **number**
## Circle
构造圆形对象,通过CircleOptions指定多边形样式
### Parameters
- `opts` **CircleOptions**
- `opts.center` **LngLat** 圆心位置
- `opts.radius` **number** 圆半径,单位:米
- `opts.zIndex` **number** 多边形覆盖物的叠加顺序。地图上存在多个多边形覆盖物叠加时,通过该属性使级别较高的多边形覆盖物在上层显示 (optional, default `10`)
- `opts.bubble` **boolean** 是否将覆盖物的鼠标或touch等事件冒泡到地图上(自v1.3 新增) (optional, default `false`)
- `opts.cursor` **string?** 指定鼠标悬停时的鼠标样式,自定义cursor,IE仅支持cur/ani/ico格式,Opera不支持自定义cursor
- `opts.strokeColor` **string** 轮廓线颜色,使用16进制颜色代码赋值。默认值为#00D3FC (optional, default `#00D3FC`)
- `opts.strokeOpacity` **number** 轮廓线透明度,取值范围[0,1],0表示完全透明,1表示不透明。默认为0.9 (optional, default `0.9`)
- `opts.strokeWeight` **number** 轮廓线宽度 (optional, default `2`)
- `opts.fillColor` **string** 多边形填充颜色,使用16进制颜色代码赋值,如:#00B2D5 (optional, default `#00B2D5`)
- `opts.fillOpacity` **number** 多边形填充透明度,取值范围[0,1],0表示完全透明,1表示不透明。默认为0.5 (optional, default `0.5`)
- `opts.draggable` **boolean** 设置多边形是否可拖拽移动,默认为false (optional, default `false`)
- `opts.extData` **object?** 用户自定义属性,支持JavaScript API任意数据类型,如Polygon的id等
- `opts.strokeStyle` **(`"solid"` \| `"dashed"`)** 轮廓线样式,实线:solid,虚线:dashed (optional, default `solid`)
- `opts.strokeDasharray` **Array<number>?** 勾勒形状轮廓的虚线和间隙的样式,此属性在strokeStyle 为dashed 时有效, 此属性在ie9+浏览器有效 取值:
实线:[0,0,0]
虚线:[10,10] ,[10,10] 表示10个像素的实线和10个像素的空白(如此反复)组成的虚线
点画线:[10,2,10], [10,2,10] 表示10个像素的实线和2个像素的空白 + 10个像素的实线和10个像素的空白 (如此反复)组成的虚线
### svgDom
### svgDom
### setCenter
设置圆中心点
#### Parameters
- `center` **LngLatLike**
### setRadius
设置圆形的半径
#### Parameters
- `radius` **number**
### getCenter
获取圆中心点
Returns **LngLat** center
### getRadius
获取圆形的半径
Returns **number** radius
### generateBuffer
#### Parameters
- `gl`
### contains
判断指定点坐标是否在圆内
#### Parameters
- `point` **LngLatLike**
Returns **boolean**
### setOptions
修改圆属性(样式风格,包括组成圆形轮廓线的节点、轮廓线样式等。属性详情参看CircleOptions列表)
#### Parameters
- `optsArg` **CircleOptions**
### hide
隐藏圆形
### show
显示圆形
### getExtData
获取用户自定义属性
Returns **Object**
### setExtData
设置用户自定义属性,支持JavaScript API任意数据类型
#### Parameters
- `extData` **Object**
### destroy
销毁内存-圆形
### getArea
获取面积,平米
Returns **number**
### getOptions
获取圆形的属性
Returns **CircleOptions**
### getPath
获取圆面路径的节点数组
Returns **(Array<LngLat> | Array<Array<LngLat>>)**
## CircleMarker
构造圆形对象,通过CircleOptions指定多边形样式
### Parameters
- `opts` **CircleMarkerOptions**
- `opts.center` **LngLat** 圆心位置
- `opts.radius` **number** 圆半径,单位:px 最大值64
- `opts.zIndex` **number** 多边形覆盖物的叠加顺序。地图上存在多个多边形覆盖物叠加时,通过该属性使级别较高的多边形覆盖物在上层显示 (optional, default `10`)
- `opts.bubble` **boolean** 是否将覆盖物的鼠标或touch等事件冒泡到地图上(自v1.3 新增) (optional, default `false`)
- `opts.cursor` **string?** 指定鼠标悬停时的鼠标样式,自定义cursor,IE仅支持cur/ani/ico格式,Opera不支持自定义cursor
- `opts.strokeColor` **string** 轮廓线颜色,使用16进制颜色代码赋值。默认值为#00D3FC (optional, default `#00D3FC`)
- `opts.strokeOpacity` **number** 轮廓线透明度,取值范围[0,1],0表示完全透明,1表示不透明。默认为0.9 (optional, default `0.9`)
- `opts.strokeWeight` **number** 轮廓线宽度 (optional, default `2`)
- `opts.fillColor` **string** 多边形填充颜色,使用16进制颜色代码赋值,如:#00B2D5 (optional, default `#00B2D5`)
- `opts.fillOpacity` **number** 多边形填充透明度,取值范围[0,1],0表示完全透明,1表示不透明。默认为0.5 (optional, default `0.5`)
- `opts.draggable` **boolean** 设置多边形是否可拖拽移动,默认为false (optional, default `false`)
- `opts.extData` **object?** 用户自定义属性,支持JavaScript API任意数据类型,如Polygon的id等
### contains
判断指定点坐标是否在圆内
#### Parameters
- `point` **LngLatLike**
Returns **boolean**
### hide
隐藏圆点
### setRadius
设置圆点的半径
#### Parameters
- `radius` **number**
### generateBuffer
### getCenter
获取圆点中心
Returns **LngLat**
### getRadius
获取圆点的半径
Returns **number**
### show
显示CircleMarker
### setOptions
修改圆点标记的属性(样式风格,包括轮廓线、填充色等。属性详情参看CircleMarkerOptions列表)
#### Parameters
- `optsArg` **CircleMarkerOptions**
### getOptions
获取圆点的属性
Returns **CircleMarkerOptions**
### getExtData
获取用户自定义属性
Returns **Object**
### setExtData
设置用户自定义属性,支持JavaScript API任意数据类型
#### Parameters
- `extData` **Object**
### destroy
销毁内存-CircleMarker
## Ellipse
**Extends \_Polygon.CombinePolygon**
### Parameters
- `opts` (optional, default `{}`)
### path
### svgDom
### setCenter
设置椭圆的中心点
#### Parameters
- `center` **LngLatLike**
### setRadius
设置椭圆的半径
#### Parameters
- `radius` **\[number, number]**
### getCenter
获取椭圆的圆心
Returns **LngLat**
### getRadius
获取椭圆的半径
Returns **number**
### generateBuffer
#### Parameters
- `gl`
### hide
隐藏椭圆
### setOptions
修改椭圆属性(样式风格,包括组成椭圆轮廓线的节点、轮廓线样式等。属性详情参看Ellipse
#### Parameters
- `optsArg` **EllipseOptions**
### show
显示椭圆
### getExtData
获取用户自定义属性
Returns **Object**
### setExtData
设置用户自定义属性,支持JavaScript API任意数据类型
#### Parameters
- `extData` **Object**
### destroy
销毁内存-椭圆
### getArea
获取面积,平米
Returns **number**
### contains
判断指定点坐标是否在椭圆内
#### Parameters
- `point` **LngLatLike**
### getOptions
获取椭圆的属性
Returns **EllipseOptions**
### getPath
获取椭圆面路径的节点数组
Returns **(Array<LngLat> | Array<Array<LngLat>>)**
## Ellipse
构造多边形对象,通过EllipseOptions指定多边形样式
### Parameters
- `opts` **EllipseOptions**
- `opts.center` **LngLatLike** 椭圆圆心
- `opts.radius` **\[number, number]** 椭圆的半径,用2个元素的数组表示,单位:米
如: radius: [1000, 2000] 表示横向半径是1000,纵向的半径是2000
默认值:[1000, 1000]
- `opts.zIndex` **number** 椭圆覆盖物的叠加顺序。地图上存在多个多边形覆盖物叠加时,通过该属性使级别较高的多边形覆盖物在上层显示 (optional, default `10`)
- `opts.bubble` **boolean** 是否将覆盖物的鼠标或touch等事件冒泡到地图上 (optional, default `false`)
- `opts.cursor` **string?** 指定鼠标悬停时的鼠标样式,自定义cursor,IE仅支持cur/ani/ico格式,Opera不支持自定义cursor
- `opts.strokeColor` **string** 线条颜色,使用16进制颜色代码赋值。默认值为#00D3FC (optional, default `#00D3FC`)
- `opts.strokeOpacity` **number** 轮廓线透明度,取值范围[0,1],0表示完全透明,1表示不透明。默认为0.9 (optional, default `0.9`)
- `opts.strokeWeight` **number** 轮廓线宽度 (optional, default `2`)
- `opts.fillColor` **string** 椭圆填充颜色,使用16进制颜色代码赋值,如:#00B2D5 (optional, default `#00B2D5`)
- `opts.fillOpacity` **number** 椭圆填充透明度,取值范围[0,1],0表示完全透明,1表示不透明。默认为0.5 (optional, default `0.5`)
- `opts.draggable` **boolean** 设置椭圆是否可拖拽移动,默认为false (optional, default `false`)
- `opts.extData` **object?** 用户自定义属性,支持JavaScript API任意数据类型,如 id 等
- `opts.strokeStyle` **(`"solid"` \| `"dashed"`)** 轮廓线样式,实线:solid,虚线:dashed (optional, default `solid`)
- `opts.strokeDasharray` **Array<number>?** 勾勒形状轮廓的虚线和间隙的样式,此属性在strokeStyle 为dashed 时有效, 此属性在ie9+浏览器有效 取值:
实线:[0,0,0]
虚线:[10,10] ,[10,10] 表示10个像素的实线和10个像素的空白(如此反复)组成的虚线
点画线:[10,2,10], [10,2,10] 表示10个像素的实线和2个像素的空白 + 10个像素的实线和10个像素的空白 (如此反复)组成的虚线
### path
### svgDom
### setCenter
设置椭圆的中心点
#### Parameters
- `center` **LngLatLike**
### setRadius
设置椭圆的半径
#### Parameters
- `radius` **\[number, number]**
### getCenter
获取椭圆的圆心
Returns **LngLat**
### getRadius
获取椭圆的半径
Returns **number**
### generateBuffer
#### Parameters
- `gl`
### hide
隐藏椭圆
### setOptions
修改椭圆属性(样式风格,包括组成椭圆轮廓线的节点、轮廓线样式等。属性详情参看Ellipse
#### Parameters
- `optsArg` **EllipseOptions**
### show
显示椭圆
### getExtData
获取用户自定义属性
Returns **Object**
### setExtData
设置用户自定义属性,支持JavaScript API任意数据类型
#### Parameters
- `extData` **Object**
### destroy
销毁内存-椭圆
### getArea
获取面积,平米
Returns **number**
### contains
判断指定点坐标是否在椭圆内
#### Parameters
- `point` **LngLatLike**
### getOptions
获取椭圆的属性
Returns **EllipseOptions**
### getPath
获取椭圆面路径的节点数组
Returns **(Array<LngLat> | Array<Array<LngLat>>)**
## Rectangle
构造矩形对象,通过RectangleOptions指定多边形样式
### Parameters
- `opts` **RectangleOptions**
- `opts.map` **Map** 要显示该覆盖物的地图对象
- `opts.bounds` **Bounds** 矩形的范围
- `opts.zIndex` **number** 矩形覆盖物的叠加顺序。地图上存在多个矩形覆盖物叠加时,通过该属性使级别较高的矩形覆盖物在上层显示 (optional, default `10`)
- `opts.bubble` **boolean** 是否将覆盖物的鼠标或touch等事件冒泡到地图上(自v1.3 新增) (optional, default `false`)
- `opts.cursor` **string?** 指定鼠标悬停时的鼠标样式,自定义cursor,IE仅支持cur/ani/ico格式,Opera不支持自定义cursor
- `opts.strokeColor` **string** 线条颜色,使用16进制颜色代码赋值。默认值为#00D3FC (optional, default `#00D3FC`)
- `opts.strokeOpacity` **number** 轮廓线透明度,取值范围[0,1],0表示完全透明,1表示不透明。默认为0.9 (optional, default `0.9`)
- `opts.strokeWeight` **number** 轮廓线宽度 (optional, default `2`)
- `opts.fillColor` **string** 矩形填充颜色,使用16进制颜色代码赋值,如:#00B2D5 (optional, default `#00B2D5`)
- `opts.fillOpacity` **number** 矩形填充透明度,取值范围[0,1],0表示完全透明,1表示不透明。默认为0.5 (optional, default `0.5`)
- `opts.draggable` **boolean** 设置矩形是否可拖拽移动,默认为false (optional, default `false`)
- `opts.extData` **object?** 用户自定义属性,支持JavaScript API任意数据类型,如Polygon的id等
- `opts.strokeStyle` **(`"solid"` \| `"dashed"`)** 轮廓线样式,实线:solid,虚线:dashed (optional, default `solid`)
- `opts.strokeDasharray` **Array<number>?** 勾勒形状轮廓的虚线和间隙的样式,此属性在strokeStyle 为dashed 时有效, 此属性在ie9+浏览器有效 取值:
实线:[0,0,0]
虚线:[10,10] ,[10,10] 表示10个像素的实线和10个像素的空白(如此反复)组成的虚线
点画线:[10,2,10], [10,2,10] 表示10个像素的实线和2个像素的空白 + 10个像素的实线和10个像素的空白 (如此反复)组成的虚线
### contains
判断坐标是否在矩形上
#### Parameters
- `point` **LngLatLike**
Returns **boolean**
### setBounds
设置矩形的范围
#### Parameters
- `bounds` **Bounds**
Returns **void**
### generateBuffer
#### Parameters
- `gl`
### setOptions
修改矩形属性(样式风格,包括组成矩形轮廓线的节点、轮廓线样式等。属性详情参看RectangleOptions列表)
#### Parameters
- `optsArg` **RectangleOptions**
### getBounds
获取当前矩形路径的节点数组。
Returns **(Array<LngLat> | Array<Array<LngLat>>)**
### getBounds
获取当前矩形的范围对象
Returns **Bounds**
### hide
隐藏矩形
### getCenter
获取矩形的中心点
Returns **LngLat**
### show
显示矩形
### getExtData
获取用户自定义属性
Returns **Object**
### setExtData
设置用户自定义属性,支持JavaScript API任意数据类型
#### Parameters
- `extData` **Object**
### destroy
销毁内存-矩形
### getArea
获取面积,平米
Returns **number**
### getOptions
获取矩形的属性
Returns **RectangleOptions**
## GeoJSON
**Extends AMap.OverlayGroup**
### Parameters
- `opts`
### importData
加载新的GeoJSON对象,转化为覆盖物,旧的覆盖物将移除
#### Parameters
- `geoJSON` **any**
### toGeoJSON
将当前对象包含的覆盖物转换为GeoJSON对象
Returns **Object** GeoJSONObject
## GeoJSON
**Extends AMap.OverlayGroup**
### Parameters
- `opts`
### importData
加载新的GeoJSON对象,转化为覆盖物,旧的覆盖物将移除
#### Parameters
- `geoJSON` **any**
### toGeoJSON
将当前对象包含的覆盖物转换为GeoJSON对象
Returns **Object** GeoJSONObject
## GeoJSON
**Extends OverlayGroup**
GeoJSON类,继承自OverLayGroup,可实现GeoJSON对象与OverlayGroup的相互转换
### Parameters
- `opts` **GeoJSONOptions** 创建一个GeoJSON对象,ops为初始构造参数
- `opts.geoJSON` **Object** 要加载的标准GeoJSON对象
- `opts.getMarker` **function (geojson, lnglat)** 指定点要素的绘制方式,缺省时为Marker的默认样式。geojson为当前要素对应的GeoJSON对象,lnglats为对应的线的路径
- `opts.getPolyline` **function (geojson, lnglat)** 指定线要素的绘制方式,缺省时为Marker的默认样式。geojson为当前要素对应的GeoJSON对象,lnglats为对应的线的路径
- `opts.getPolygon` **function (geojson, lnglat)** 指定面要素的绘制方式,缺省时为Marker的默认样式。geojson为当前要素对应的GeoJSON对象,lnglats为对应的线的路径
### importData
加载新的GeoJSON对象,转化为覆盖物,旧的覆盖物将移除
#### Parameters
- `geoJSON` **any**
### toGeoJSON
将当前对象包含的覆盖物转换为GeoJSON对象
Returns **Object** GeoJSONObject
FILE:references/context-menu.md
# 右键菜单 (ContextMenu)
右键菜单可以绑定到地图底图或覆盖物上,提供快捷操作功能。
## 创建菜单
```javascript
// 创建右键菜单实例
const contextMenu = new AMap.ContextMenu();
// 添加菜单项
contextMenu.addItem('放大一级', function() {
map.zoomIn();
}, 0); // 第三个参数是排序权重
contextMenu.addItem('缩小一级', function() {
map.zoomOut();
}, 1);
contextMenu.addItem('设置中心点', function() {
map.setCenter(contextMenuPos); // 使用保存的点击位置
}, 2);
```
## 绑定事件
### 1. 绑定到地图
```javascript
let contextMenuPos;
map.on('rightclick', function(e) {
contextMenuPos = e.lnglat; // 记录右键点击的位置
contextMenu.open(map, e.lnglat);
});
```
### 2. 绑定到覆盖物 (如 Marker)
```javascript
const marker = new AMap.Marker({
position: [116.397, 39.909]
});
map.add(marker);
const markerMenu = new AMap.ContextMenu();
markerMenu.addItem('删除标记', function() {
map.remove(marker);
});
marker.on('rightclick', function(e) {
markerMenu.open(map, e.lnglat);
});
```
## 动态菜单
你可以在事件回调中动态修改菜单项。
```javascript
map.on('rightclick', function(e) {
contextMenu.removeItem('添加标记', function(){}); // 先移除旧的(如果需要)
// 根据条件动态添加
if (map.getZoom() < 10) {
contextMenu.addItem('缩放至详细级别', () => map.setZoom(15), 0);
}
contextMenu.open(map, e.lnglat);
});
```
FILE:references/custom-layers.md
# 自定义图层 (Custom Layers)
当官方图层无法满足需求时,可以使用自定义图层叠加自己的数据。
## 1. 图片图层 (ImageLayer)
将一张图片映射到地图的指定区域(矩形范围)。
```javascript
const bounds = new AMap.Bounds(
[116.327911, 39.939229], // 西南角
[116.342659, 39.946275] // 东北角
);
const imageLayer = new AMap.ImageLayer({
url: 'https://amap.com/examples/img/dongwuyuan.jpg',
bounds: bounds,
zooms: [12, 20],
zIndex: 2,
opacity: 0.8
});
map.add(imageLayer);
```
## 2. 视频图层 (VideoLayer)
将视频流叠加到地图上,支持 HTML5 Video 元素。
```javascript
const videoLayer = new AMap.VideoLayer({
url: 'https://xxx.mp4', // 视频地址
bounds: bounds,
zIndex: 10,
zooms: [14, 20],
opacity: 1,
loop: true, // 是否循环播放
});
map.add(videoLayer);
```
## 3. Canvas 图层 (CanvasLayer)
最灵活的图层,允许通过 Canvas API 自定义绘制内容。
```javascript
const canvas = document.createElement('canvas');
canvas.width = map.getSize().width;
canvas.height = map.getSize().height;
const canvasLayer = new AMap.CanvasLayer({
canvas: canvas,
bounds: map.getBounds(),
zooms: [3, 18],
});
map.add(canvasLayer);
// 自定义绘制逻辑
function draw() {
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
// ... 绘制逻辑 ...
// 可以使用 AMap.CustomLayer 的 render 方法结合 map.lngLatToContainer 转换坐标
}
draw();
```
## 4. 自定义切片图层 (TileLayer)
加载第三方的 WMTS 或 XYZ 切片服务。
```javascript
const xyzLayer = new AMap.TileLayer({
// [x], [y], [z] 会自动替换为行列号和缩放级别
getTileUrl: 'https://tile.openstreetmap.org/[z]/[x]/[y].png',
zIndex: 100
});
map.add(xyzLayer);
```
## 5. GL 图层 (GLCustomLayer)
结合 Three.js 实现自定义 3D 场景渲染。
```javascript
var map = new AMap.Map('container', {
center: [116.54, 39.79],
zooms: [2, 20],
zoom: 14,
viewMode: '3D',
pitch: 50,
});
var camera;
var renderer;
var scene;
var meshes = [];
// 数据转换工具
var customCoords = map.customCoords;
// 数据使用转换工具进行转换,这个操作必须要提前执行(在获取镜头参数 函数之前执行),否则将会获得一个错误信息。
var data = customCoords.lngLatsToCoords([
[116.52, 39.79],
[116.54, 39.79],
[116.56, 39.79],
]);
// 创建 GL 图层
var gllayer = new AMap.GLCustomLayer({
// 图层的层级
zIndex: 10,
// 初始化的操作,创建图层过程中执行一次。
init: (gl) => {
// 这里我们的地图模式是 3D,所以创建一个透视相机,相机的参数初始化可以随意设置,因为在 render 函数中,每一帧都需要同步相机参数,因此这里变得不那么重要。
// 如果你需要 2D 地图(viewMode: '2D'),那么你需要创建一个正交相机
camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
100,
1 << 30
);
renderer = new THREE.WebGLRenderer({
context: gl, // 地图的 gl 上下文
// alpha: true,
// antialias: true,
// canvas: gl.canvas,
});
// 自动清空画布这里必须设置为 false,否则地图底图将无法显示
renderer.autoClear = false;
scene = new THREE.Scene();
// 环境光照和平行光
var aLight = new THREE.AmbientLight(0xffffff, 0.3);
var dLight = new THREE.DirectionalLight(0xffffff, 1);
dLight.position.set(1000, -100, 900);
scene.add(dLight);
scene.add(aLight);
var texture = new THREE.TextureLoader().load(
'https://a.amap.com/jsapi_demos/static/demo-center-v2/three.jpeg'
);
texture.minFilter = THREE.LinearFilter;
// 这里可以使用 three 的各种材质
var mat = new THREE.MeshPhongMaterial({
color: 0xfff0f0,
depthTest: true,
transparent: true,
map: texture,
});
var geo = new THREE.BoxBufferGeometry(1000, 1000, 1000);
for (let i = 0; i < data.length; i++) {
const d = data[i];
var mesh = new THREE.Mesh(geo, mat);
mesh.position.set(d[0], d[1], 500);
meshes.push({
mesh,
count: i,
});
scene.add(mesh);
}
},
render: () => {
// 这里必须执行!!重新设置 three 的 gl 上下文状态。
renderer.resetState();
// 重新设置图层的渲染中心点,将模型等物体的渲染中心点重置
// 否则和 LOCA 可视化等多个图层能力使用的时候会出现物体位置偏移的问题
customCoords.setCenter([116.52, 39.79]);
var { near, far, fov, up, lookAt, position } =
customCoords.getCameraParams();
// 2D 地图下使用的正交相机
// var { near, far, top, bottom, left, right, position, rotation } = customCoords.getCameraParams();
// 这里的顺序不能颠倒,否则可能会出现绘制卡顿的效果。
camera.near = near;
camera.far = far;
camera.fov = fov;
camera.position.set(...position);
camera.up.set(...up);
camera.lookAt(...lookAt);
camera.updateProjectionMatrix();
// 2D 地图使用的正交相机参数赋值
// camera.top = top;
// camera.bottom = bottom;
// camera.left = left;
// camera.right = right;
// camera.position.set(...position);
// camera.updateProjectionMatrix();
renderer.render(scene, camera);
// 这里必须执行!!重新设置 three 的 gl 上下文状态。
renderer.resetState();
},
});
map.add(gllayer);
// 动画
function animate() {
for (let i = 0; i < meshes.length; i++) {
let { mesh, count } = meshes[i];
count += 1;
mesh.rotateZ((count / 180) * Math.PI);
}
map.render();
requestAnimationFrame(animate);
}
animate();
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
window.addEventListener('resize', onWindowResize);
```
FILE:references/events.md
# 事件系统 (Event System)
JSAPI v2.0 提供了一套类似于 DOM 的事件机制,支持对地图及覆盖物进行事件绑定和解绑。
## 事件绑定 (on)
```javascript
// 绑定地图点击事件
const clickHandler = function(e) {
console.log('点击位置:', e.lnglat.getLng(), e.lnglat.getLat());
console.log('触发对象:', e.target);
console.log('像素坐标:', e.pixel);
};
map.on('click', clickHandler);
// 绑定覆盖物事件
marker.on('mouseover', function(e) {
marker.setLabel({ content: '鼠标移入' });
});
```
## 事件解绑 (off)
**注意**: 解绑时需要传入绑定时的**同一个函数引用**。
```javascript
// 正确方式
map.off('click', clickHandler);
## 一次性事件 (once)
事件只触发一次后自动解绑。
```javascript
map.once('click', function(e) {
console.log('只触发一次');
});
```
## 常用事件列表
### 地图事件 (Map Events)
| 事件名 | 说明 | 回调参数 |
| :--- | :--- | :--- |
| complete | 地图资源加载完成 | - |
| click | 左键单击 | MapsEvent |
| dblclick | 左键双击 | MapsEvent |
| rightclick | 右键单击 | MapsEvent |
| mousemove | 鼠标移动 | MapsEvent |
| mousewheel | 鼠标滚轮 | MapsEvent |
| mouseover | 鼠标移入 | MapsEvent |
| mouseout | 鼠标移出 | MapsEvent |
| mousedown | 鼠标按下 | MapsEvent |
| mouseup | 鼠标抬起 | MapsEvent |
| touchstart | 触摸开始 | MapsEvent |
| touchmove | 触摸移动 | MapsEvent |
| touchend | 触摸结束 | MapsEvent |
| zoomstart | 缩放开始 | - |
| zoomend | 缩放结束 | - |
| zoomchange | 缩放级别变化 | - |
| movestart | 平移开始 | - |
| moveend | 平移结束 | - |
| mapmove | 地图移动中 | - |
| rotatestart | 旋转开始 | - |
| rotateend | 旋转结束 | - |
| rotatechange | 旋转角度变化 | - |
| dragstart | 拖拽开始 | - |
| dragging | 拖拽中 | - |
| dragend | 拖拽结束 | - |
| resize | 地图容器大小变化 | - |
| hotspotclick | 热点点击 | { type, lnglat, name, id } |
| hotspotover | 热点移入 | { type, lnglat, name, id } |
| hotspotout | 热点移出 | { type, lnglat, name, id } |
### 覆盖物事件 (Overlay Events)
适用于 `Marker`, `Polygon`, `Polyline`, `Circle` 等。
| 事件名 | 说明 |
| :--- | :--- |
| `click` | 点击覆盖物 |
| `mouseover` | 鼠标移入 |
| `mouseout` | 鼠标移出 |
| `dragstart` | 开始拖拽 (需设置 `draggable: true`) |
| `dragging` | 拖拽中 |
| `dragend` | 拖拽结束 |
## 完整示例
### 基础事件监听
```javascript
const map = new AMap.Map('container', {
zoom: 14,
center: [116.397, 39.909]
});
// 地图加载完成
map.on('complete', function() {
console.log('地图加载完成');
});
// 点击事件
map.on('click', function(e) {
console.log('点击坐标:', e.lnglat.getLng(), e.lnglat.getLat());
// 在点击位置添加标记
new AMap.Marker({
map: map,
position: e.lnglat
});
});
// 缩放事件
map.on('zoomend', function() {
console.log('当前缩放级别:', map.getZoom());
});
// 移动事件
map.on('moveend', function() {
console.log('当前中心点:', map.getCenter());
});
```
### 覆盖物事件
```javascript
const marker = new AMap.Marker({
position: [116.397, 39.909],
draggable: true
});
map.add(marker);
// 点击事件
marker.on('click', function(e) {
console.log('点击了标记');
});
// 鼠标移入移出
marker.on('mouseover', function() {
marker.setLabel({ content: '鼠标移入' });
});
marker.on('mouseout', function() {
marker.setLabel({ content: '' });
});
// 拖拽事件
marker.on('dragstart', function() {
console.log('开始拖拽');
});
marker.on('dragend', function(e) {
console.log('拖拽结束,新位置:', e.target.getPosition());
});
```
## 自定义事件上下文
可以通过 `context` 参数指定回调函数中的 `this` 指向。
```javascript
map.on('click', function() {
this.foo(); // this 指向 myObj
}, myObj);
```
## 注意事项
1. **函数引用**: 解绑事件时必须传入绑定时的同一个函数引用
2. **避免匿名函数**: 如果需要解绑,不要使用匿名函数
3. **内存管理**: 组件销毁前解绑事件,防止内存泄漏
4. **事件冒泡**: 覆盖物事件会冒泡到地图,必要时阻止冒泡
5. **触摸事件**: 移动端需要监听 touch 系列事件
6. **异步加载**: complete 事件在地图资源加载完成后触发
FILE:references/geocoder.md
# 地理编码 (Geocoder)
地理编码服务提供了将地址转换为经纬度(正向地理编码)和将经纬度转换为地址(逆向地理编码)的功能。
## 1. 加载插件
使用 `AMapLoader` 加载时需要包含 `AMap.Geocoder` 插件。
```javascript
AMapLoader.load({
key: '您的Key',
version: '2.0',
plugins: ['AMap.Geocoder'] // 预加载插件
}).then((AMap) => {
// ...
});
```
## 2. 正向地理编码 (地址 -> 坐标)
将详细的结构化地址转换为经纬度坐标。
```javascript
const geocoder = new AMap.Geocoder({
city: '010', // 城市,默认全国
});
geocoder.getLocation('北京市朝阳区阜通东大街6号', function(status, result) {
if (status === 'complete' && result.info === 'OK') {
// result.geocodes 是一个数组
const { location, formattedAddress } = result.geocodes[0];
console.log('坐标:', location.lng, location.lat);
console.log('规范地址:', formattedAddress);
// 在地图上标记
map.setCenter(location);
new AMap.Marker({
map: map,
position: location
});
} else {
console.error('地理编码失败');
}
});
```
## 3. 逆向地理编码 (坐标 -> 地址)
将经纬度坐标转换为详细地址信息。
```javascript
const lnglat = [116.396574, 39.992706];
geocoder.getAddress(lnglat, function(status, result) {
if (status === 'complete' && result.info === 'OK') {
// result.regeocode 包含详细地址信息
const address = result.regeocode.formattedAddress;
console.log('地址:', address);
// 获取周边 POI、道路等详细信息
const { roads, pois, aois } = result.regeocode.addressComponent;
} else {
console.error('逆地理编码失败');
}
});
```
## 完整示例
### 地址搜索定位
```javascript
const map = new AMap.Map('container', {
zoom: 14,
center: [116.397, 39.909]
});
const geocoder = new AMap.Geocoder({
city: '北京',
extensions: 'all'
});
const input = document.getElementById('addressInput');
const btn = document.getElementById('searchBtn');
btn.onclick = function() {
const address = input.value.trim();
if (!address) return;
geocoder.getLocation(address, function(status, result) {
if (status === 'complete' && result.geocodes.length > 0) {
const geocode = result.geocodes[0];
// 清除之前的标记
map.clearMap();
// 添加标记
const marker = new AMap.Marker({
map: map,
position: geocode.location
});
// 信息窗体
const infoWindow = new AMap.InfoWindow({
content: `
<div>
<h4>geocode.formattedAddress</h4>
<p>坐标: geocode.location.lng, geocode.location.lat</p>
</div>
`,
offset: new AMap.Pixel(0, -30)
});
marker.on('click', function() {
infoWindow.open(map, marker.getPosition());
});
// 移动视角
map.setZoomAndCenter(16, geocode.location);
// 自动打开信息窗体
infoWindow.open(map, geocode.location);
} else {
alert('未找到该地址');
}
});
};
```
### 点击地图获取地址
```javascript
const map = new AMap.Map('container', {
zoom: 14,
center: [116.397, 39.909]
});
const geocoder = new AMap.Geocoder({
extensions: 'all'
});
const infoWindow = new AMap.InfoWindow({
offset: new AMap.Pixel(0, -15)
});
map.on('click', function(e) {
const lnglat = [e.lnglat.getLng(), e.lnglat.getLat()];
geocoder.getAddress(lnglat, function(status, result) {
if (status === 'complete') {
const address = result.regeocode.formattedAddress;
infoWindow.setContent(`
<div style="padding: 10px;">
<p><strong>地址:</strong> address</p>
<p><strong>坐标:</strong> lnglat[0].toFixed(6), lnglat[1].toFixed(6)</p>
</div>
`);
infoWindow.open(map, e.lnglat);
}
});
});
```
## 注意事项
1. **城市限制**: 设置 city 可以提高编码准确度
2. **详细信息**: 需要 POI、道路等信息时设置 `extensions: 'all'`
3. **批量查询**: 批量查询需要设置 `batch: true`
4. **结果数量**: 正向编码可能返回多个结果,需要根据 level 判断准确度
5. **坐标格式**: 逆向编码支持数组 `[lng, lat]` 或 LngLat 对象
FILE:references/info-window.md
# 信息窗体 (InfoWindow)
信息窗体用于在地图上弹出一个浮层,展示详细信息。它可以绑定到特定位置或覆盖物上。
## 基础用法
```javascript
// 1. 创建信息窗体
const infoWindow = new AMap.InfoWindow({
content: '<h4>标题</h4><div>这是信息窗体的内容</div>', // 支持 HTML 字符串或 DOM 元素
anchor: 'bottom-center', // 锚点位置: top-left, top-center, top-right, middle-left, center, middle-right, bottom-left, bottom-center, bottom-right
offset: new AMap.Pixel(0, -30), // 偏移量,避免遮挡标记
isCustom: false, // 是否自定义外观 (设为 true 则不显示默认边框和关闭按钮)
autoMove: true, // 是否自动调整地图视野使窗体可见
closeWhenClickMap: true, // 点击地图其他空白处关闭窗体
});
// 2. 打开信息窗体
infoWindow.open(map, [116.397, 39.909]); // 在指定位置打开
// 或者绑定点击事件
marker.on('click', function(e) {
infoWindow.open(map, e.target.getPosition());
});
```
## 自定义样式
如果将 `isCustom` 设为 `true`,则可以完全控制窗体的外观。
```javascript
const customInfoWindow = new AMap.InfoWindow({
isCustom: true,
content: createCustomContent(), // 返回一个 DOM 元素
offset: new AMap.Pixel(16, -45)
});
function createCustomContent() {
const div = document.createElement('div');
div.className = 'my-info-window';
div.innerHTML = `
<div class="info-title">高德地图</div>
<div class="info-body">自定义样式的窗体</div>
<button onclick="closeInfoWindow()">关闭</button>
`;
return div;
}
// 需要手动实现关闭逻辑
window.closeInfoWindow = function() {
map.clearInfoWindow();
}
```
## 更新内容
```javascript
infoWindow.setContent('<div>新的内容</div>');
infoWindow.setPosition([116.40, 39.90]);
```
## 配置项
| 参数 | 类型 | 默认值 | 说明 |
| :--- | :--- | :--- | :--- |
| content | String/HTMLElement | - | 内容,支持 HTML 字符串或 DOM 元素 |
| anchor | String | 'bottom-center' | 锚点位置 |
| offset | Pixel | - | 偏移量 |
| isCustom | Boolean | false | 是否自定义样式 |
| autoMove | Boolean | false | 是否自动调整地图视野 |
| closeWhenClickMap | Boolean | false | 点击地图其他区域是否关闭 |
| size | Size | - | 窗体大小 |
| avoid | Array | - | 避让的像素区域 |
### 锚点位置 (anchor)
- `top-left` - 左上
- `top-center` - 上中
- `top-right` - 右上
- `middle-left` - 左中
- `center` - 中心
- `middle-right` - 右中
- `bottom-left` - 左下
- `bottom-center` - 下中(默认)
- `bottom-right` - 右下
## 与标记配合使用
```javascript
const marker = new AMap.Marker({
position: [116.397, 39.909],
title: '点击查看详情'
});
map.add(marker);
const infoWindow = new AMap.InfoWindow({
content: '<div>POI 详情信息</div>',
offset: new AMap.Pixel(0, -30)
});
marker.on('click', function(e) {
infoWindow.open(map, e.target.getPosition());
});
```
## 自定义样式
设置 `isCustom: true` 完全控制窗体外观:
```javascript
const customInfoWindow = new AMap.InfoWindow({
isCustom: true,
content: createCustomContent(),
offset: new AMap.Pixel(16, -45)
});
function createCustomContent() {
const div = document.createElement('div');
div.className = 'custom-info-window';
div.innerHTML = `
<div class="info-header">
<span class="info-title">高德地图</span>
<span class="info-close" onclick="closeInfoWindow()">×</span>
</div>
<div class="info-body">
<p>自定义样式的信息窗体</p>
<button onclick="doSomething()">操作按钮</button>
</div>
<div class="info-arrow"></div>
`;
return div;
}
// 全局关闭方法
window.closeInfoWindow = function() {
map.clearInfoWindow();
};
```
### 自定义样式 CSS
```css
.custom-info-window {
background: #fff;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
min-width: 200px;
position: relative;
}
.info-header {
background: linear-gradient(135deg, #1890ff, #096dd9);
color: #fff;
padding: 12px 16px;
border-radius: 8px 8px 0 0;
display: flex;
justify-content: space-between;
align-items: center;
}
.info-title {
font-weight: 600;
}
.info-close {
cursor: pointer;
font-size: 18px;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
}
.info-close:hover {
background: rgba(255,255,255,0.2);
}
.info-body {
padding: 16px;
}
.info-arrow {
position: absolute;
bottom: -8px;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
border-top: 8px solid #fff;
}
```
## 动态更新内容
```javascript
// 更新内容
infoWindow.setContent('<div>新的内容</div>');
// 更新位置
infoWindow.setPosition([116.40, 39.90]);
// 获取当前位置
const position = infoWindow.getPosition();
// 获取是否打开
const isOpen = infoWindow.getIsOpen();
```
## 事件监听
```javascript
infoWindow.on('open', function() {
console.log('信息窗体已打开');
});
infoWindow.on('close', function() {
console.log('信息窗体已关闭');
});
infoWindow.on('change', function() {
console.log('信息窗体内容或位置已改变');
});
```
## 完整示例
```javascript
const map = new AMap.Map('container', {
zoom: 14,
center: [116.397, 39.909]
});
// POI 数据
const pois = [
{ name: '天安门', address: '北京市东城区', position: [116.397428, 39.90923] },
{ name: '故宫', address: '北京市东城区景山前街4号', position: [116.397026, 39.918058] },
{ name: '王府井', address: '北京市东城区', position: [116.410904, 39.913904] }
];
// 创建信息窗体
const infoWindow = new AMap.InfoWindow({
isCustom: true,
offset: new AMap.Pixel(0, -40)
});
// 添加标记
pois.forEach(poi => {
const marker = new AMap.Marker({
position: poi.position,
title: poi.name
});
marker.on('click', function(e) {
const content = `
<div class="poi-info-window">
<div class="poi-header">
<h3>poi.name</h3>
<span class="close-btn" onclick="map.clearInfoWindow()">×</span>
</div>
<div class="poi-body">
<p>poi.address</p>
<div class="poi-actions">
<button onclick="navigateTo(poi.position[0], poi.position[1])">导航</button>
<button onclick="shareLocation('poi.name')">分享</button>
</div>
</div>
</div>
`;
infoWindow.setContent(content);
infoWindow.open(map, e.target.getPosition());
});
map.add(marker);
});
// 全局方法
window.navigateTo = function(lng, lat) {
console.log('导航到:', lng, lat);
};
window.shareLocation = function(name) {
console.log('分享位置:', name);
};
```
## 关闭信息窗体
```javascript
// 方式一:调用 close 方法
infoWindow.close();
// 方式二:清除地图上的信息窗体
map.clearInfoWindow();
```
## 注意事项
1. **同时只能打开一个**: 地图上同时只能打开一个信息窗体
2. **自定义样式**: `isCustom: true` 时不显示默认的边框和关闭按钮
3. **偏移量**: 根据标记图标大小调整 offset,避免遮挡
4. **自动调整**: `autoMove: true` 可以自动调整地图视野使窗体可见
5. **事件冒泡**: 窗体内的点击事件需要阻止冒泡,否则可能触发地图点击事件
FILE:references/layers.md
# 官方图层 (Official Layers)
高德地图 JSAPI v2.0 内置了多种标准图层,开发者可以按需叠加使用。
## 1. 标准切片图层 (TileLayer)
基础的栅格瓦片图层。
```javascript
// 默认标准图层
const layer = new AMap.TileLayer();
map.add(layer);
```
### 衍生图层
- **卫星图层 (Satellite)**
```javascript
const satellite = new AMap.TileLayer.Satellite();
map.add(satellite);
```
- **路网图层 (RoadNet)**
通常叠加在卫星图上使用,展示道路网络。
```javascript
const roadNet = new AMap.TileLayer.RoadNet();
map.add(roadNet);
```
- **实时路况图层 (Traffic)**
展示实时的交通拥堵情况。
```javascript
const traffic = new AMap.TileLayer.Traffic({
zIndex: 10,
autoRefresh: true, // 是否自动刷新
interval: 180, // 刷新间隔 (秒)
});
map.add(traffic);
```
## 2. 3D 楼块图层 (Buildings)
用于展示 3D 建筑物模型,仅在 `viewMode: '3D'` 下有效。
```javascript
const buildings = new AMap.Buildings({
zooms: [16, 20], // 显示层级范围
zIndex: 10,
heightFactor: 2, // 楼块高度系数
});
map.add(buildings);
// 设置楼块样式
buildings.setStyle({
hideWithoutStyle: false, // 是否隐藏未设置样式的楼块
areas: [{
color1: 'red', // 顶面颜色
color2: 'blue', // 侧面颜色
path: [[116.403322, 39.920255], ...], // 围栏区域
}]
});
```
## 3. 室内地图图层 (IndoorMap)
当缩放级别达到一定程度且地图中心位于支持室内地图的建筑(如大型商场、机场)时自动显示。
```javascript
const indoor = new AMap.IndoorMap({
alwaysShow: true, // 是否始终显示
});
map.add(indoor);
// 监听楼层切换
indoor.on('floor_change', function(e) {
console.log('当前楼层:', e.floor);
});
```
FILE:references/map-init.md
# 地图加载与初始化 (Map Initialization)
本指南介绍如何使用 `@amap/amap-jsapi-loader` 异步加载高德地图 JSAPI v2.0,并初始化地图实例。
## 前置条件
在加载地图前,**必须**先完成安全配置。请参考 [安全配置文档](./security.md)。
```javascript
// 必须在加载前执行
window._AMapSecurityConfig = {
securityJsCode: '您的安全密钥',
};
```
## 1. 引入加载器
使用 script 标签加载 loader.js:
```bash
<script src="https://webapi.amap.com/loader.js"></script>
```
## 2. 异步加载 JSAPI
使用 `AMapLoader.load` 方法加载 API。
```javascript
import AMapLoader from '@amap/amap-jsapi-loader';
AMapLoader.load({
key: '您的Key', // 必填,申请的 Web 端开发者 Key
version: '2.0', // 必填,指定版本号
plugins: ['AMap.Scale'], // 预加载插件列表
}).then((AMap) => {
// JSAPI 加载完成,可以开始初始化地图
initMap(AMap);
}).catch((e) => {
console.error('地图加载失败', e);
});
```
## 3. 进阶配置 (Advanced Configuration)
### 加载 Loca 数据可视化库
Loca 是高德地图基于 WebGL 的高性能数据可视化库。需要在加载器中显式声明 `Loca` 配置。
```javascript
AMapLoader.load({
key: '您的Key',
version: '2.0',
Loca: {
version: '2.0.0' // 指定 Loca 版本
}
}).then((AMap) => {
const map = new AMap.Map('container');
// 初始化 Loca 容器
const loca = new Loca.Container({
map: map,
});
});
```
```
### 加载器参数详解
| 参数 | 类型 | 必填 | 说明 |
| :--- | :--- | :--- | :--- |
| `key` | String | 是 | 申请好的 Web 端开发者 Key |
| `version` | String | 是 | 指定要加载的 JSAPI 版本,如 "2.0" |
| `plugins` | Array | 否 | 需要预加载的插件列表,如 `['AMap.Scale', 'AMap.ToolBar']` |
| `Loca` | Object | 否 | Loca 库配置,包含 `{ version: '2.0.0' }` |
| `AMapUI` | Object | 否 | AMapUI 库配置,包含 `{ version: '1.1', plugins: [] }` |
| `serviceHost` | String | 否 | 代理服务器地址(通常在安全配置中全局设置,此处也可覆盖) |
## 3. 初始化地图实例
创建 `AMap.Map` 实例,建议开启 3D 视图模式以获得最佳性能。
```javascript
function initMap(AMap) {
const map = new AMap.Map('container', {
viewMode: '3D', // 开启 3D 模式 (推荐)
zoom: 11, // 初始化缩放级别 [2, 20]
center: [116.397428, 39.90923], // 初始化中心点坐标 [lng, lat]
pitch: 45, // 俯仰角度,有效范围 [0, 83]
rotation: 0, // 旋转角度
mapStyle: 'amap://styles/normal', // 地图样式
});
// 添加控件
map.addControl(new AMap.Scale());
}
```
### 常用配置项
| 参数 | 类型 | 默认值 | 说明 |
| :--- | :--- | :--- | :--- |
| viewMode | String | '2D' | 渲染模式:'2D' 或 '3D' |
| zoom | Number | - | 初始缩放级别 |
| center | Array | - | 初始中心点 [lng, lat] |
| pitch | Number | 0 | 俯仰角度 (3D 模式有效) |
| rotation | Number | 0 | 旋转角度 |
| mapStyle | String | - | 地图样式 URL |
| zooms | Array | [2, 20] | 缩放级别范围 |
## 4. 地图生命周期管理
### 地图加载完成
```javascript
map.on('complete', function() {
console.log('地图加载完成');
});
```
### 销毁地图
在组件卸载或不再需要地图时,务必调用 `destroy` 方法以释放 WebGL 上下文和内存资源。
```javascript
// 销毁地图实例
if (map) {
map.destroy();
map = null;
}
```
## 5. 地图样式
### 官方主题样式
```javascript
const map = new AMap.Map('container', {
mapStyle: 'amap://styles/normal', // 标准
// mapStyle: 'amap://styles/dark', // 幻影黑
// mapStyle: 'amap://styles/light', // 月光银
// mapStyle: 'amap://styles/whitesmoke',// 远山黛
// mapStyle: 'amap://styles/fresh', // 草色青
// mapStyle: 'amap://styles/grey', // 雅士灰
// mapStyle: 'amap://styles/graffiti', // 涂鸦
// mapStyle: 'amap://styles/macaron', // 马卡龙
// mapStyle: 'amap://styles/blue', // 靛青蓝
// mapStyle: 'amap://styles/darkblue', // 极夜蓝
// mapStyle: 'amap://styles/wine', // 酱籽
});
// 动态切换样式
map.setMapStyle('amap://styles/dark');
```
## 完整示例 (Vue 3)
```vue
<template>
<div id="map-container" style="width: 100%; height: 500px;"></div>
</template>
<script setup>
import { onMounted, onUnmounted, shallowRef } from 'vue';
import AMapLoader from '@amap/amap-jsapi-loader';
const map = shallowRef(null); // 使用 shallowRef 避免深层响应式带来的性能损耗
onMounted(() => {
window._AMapSecurityConfig = { securityJsCode: '您的安全密钥' };
AMapLoader.load({
key: '您的Key',
version: '2.0',
plugins: ['AMap.Scale'], // 按需加载插件
}).then((AMap) => {
map.value = new AMap.Map('map-container', {
viewMode: '3D',
zoom: 12,
center: [120.15, 30.28],
});
// 添加插件
map.value.addControl(new AMap.Scale());
}).catch(e => console.error(e));
});
onUnmounted(() => {
map.value?.destroy();
});
</script>
```
## 5. 地图控件
```javascript
// 比例尺
map.addControl(new AMap.Scale());
// 工具条(缩放、定位)
map.addControl(new AMap.ToolBar({
position: 'RT' // 右上角
}));
// 3D 控制(旋转、俯仰)
map.addControl(new AMap.ControlBar({
position: { right: '10px', top: '10px' }
}));
// 鹰眼(缩略图)
map.addControl(new AMap.HawkEye());
// 图层切换
map.addControl(new AMap.MapType());
```
## 完整示例 (React Hooks)
```jsx
import React, { useEffect, useRef } from 'react';
import AMapLoader from '@amap/amap-jsapi-loader';
export default function MapComponent() {
const mapRef = useRef(null);
useEffect(() => {
// 安全密钥配置
window._AMapSecurityConfig = { securityJsCode: '您的安全密钥' };
AMapLoader.load({
key: '您的Key',
version: '2.0',
plugins: ['AMap.Scale'], // 预加载插件
}).then((AMap) => {
mapRef.current = new AMap.Map('map-container', {
viewMode: '3D',
zoom: 11,
center: [116.397428, 39.90923],
});
// 添加控件
mapRef.current.addControl(new AMap.Scale());
}).catch((e) => {
console.error('地图加载失败', e);
});
// 销毁地图
return () => {
mapRef.current?.destroy();
};
}, []);
return <div id="map-container" style={{ width: '100%', height: '500px' }} />;
}
```
FILE:references/marker.md
# 点标记 (Markers)
高德地图 JSAPI v2.0 提供了多种类型的点标记,适用于不同的业务场景。
## 1. 基础点标记 (Marker)
最常用的点标记,支持自定义图标或 DOM 内容。
```javascript
// 默认蓝色水滴图标
const marker = new AMap.Marker({
position: [116.397, 39.909], // 位置
icon: new AMap.Icon({
size: new AMap.Size(40, 50),
image: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png',
imageSize: new AMap.Size(40, 50),
}),
title: '北京', // 鼠标悬停文本
});
map.add(marker);
// 自定义图标
const iconMarker = new AMap.Marker({
position: [116.397, 39.909],
icon: new AMap.Icon({
size: new AMap.Size(40, 50),
image: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png',
imageSize: new AMap.Size(40, 50),
}),
offset: new AMap.Pixel(-20, -50), // 锚点偏移
});
// 自定义 DOM 内容 (灵活性最强,但性能消耗较高)
const contentMarker = new AMap.Marker({
position: [116.397, 39.909],
content: '<div class="custom-marker">我的标记</div>',
offset: new AMap.Pixel(-15, -15),
});
```
### 自定义图标样式
以下是几种常用的 Marker 样式,可直接复制使用。
#### 带徽标的定位点
适用于用户头像、 Logo 等场景。
```javascript
const marker = new AMap.Marker({
position: [116.397, 39.909],
content: `
<div class="avatar-marker">
<img src="https://example.com/avatar.jpg" alt="头像" />
<span class="status online"></span>
</div>
`,
offset: new AMap.Pixel(-20, -20),
});
```
```css
.avatar-marker {
position: relative;
width: 40px;
height: 40px;
}
.avatar-marker img {
width: 40px;
height: 40px;
border-radius: 50%;
border: 2px solid #fff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
object-fit: cover;
}
.avatar-marker .status {
position: absolute;
bottom: 2px;
right: 2px;
width: 10px;
height: 10px;
border-radius: 50%;
border: 2px solid #fff;
}
.avatar-marker .status.online { background: #52c41a; }
.avatar-marker .status.offline { background: #999; }
.avatar-marker .status.busy { background: #f5222d; }
```
#### 信息卡片式 Marker
适用于 POI 展示、信息等场景。
```javascript
const marker = new AMap.Marker({
position: [116.397, 39.909],
content: `
<div class="card-marker">
<div class="card-content">
<span class="card-price">¥288</span>
<span class="card-unit">/晚</span>
</div>
<div class="card-arrow"></div>
</div>
`,
offset: new AMap.Pixel(-40, -52),
});
```
```css
.card-marker {
position: relative;
cursor: pointer;
transition: transform 0.2s;
}
.card-marker:hover {
transform: scale(1.05);
}
.card-content {
background: #fff;
border-radius: 8px;
padding: 6px 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
white-space: nowrap;
}
.card-price {
font-size: 14px;
font-weight: 600;
color: #1890ff;
}
.card-unit {
font-size: 12px;
color: #999;
}
.card-arrow {
position: absolute;
bottom: -6px;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-top: 6px solid #fff;
}
/* 选中状态 */
.card-marker.active .card-content {
background: #1890ff;
}
.card-marker.active .card-price,
.card-marker.active .card-unit {
color: #fff;
}
.card-marker.active .card-arrow {
border-top-color: #1890ff;
}
```
#### 带数字序号的 Marker
适用于路线规划、排序展示等场景。
```javascript
function createNumberMarker(number, isStart = false, isEnd = false) {
let bgColor = '#1890ff';
if (isStart) bgColor = '#52c41a';
if (isEnd) bgColor = '#f5222d';
return new AMap.Marker({
position: [116.397, 39.909],
content: `
<div class="number-marker" style="background: bgColor">
<span>number</span>
</div>
`,
offset: new AMap.Pixel(-15, -15),
});
}
// 使用示例
const startMarker = createNumberMarker('起', true);
const endMarker = createNumberMarker('终', false, true);
const waypoint = createNumberMarker(1);
```
```css
.number-marker {
width: 30px;
height: 30px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 14px;
font-weight: 600;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
border: 2px solid #fff;
}
```
#### 分类图标 Marker
适用于 POI 分类展示。
```javascript
// 定义分类图标
const categoryIcons = {
restaurant: { icon: '🍽️', color: '#fa8c16' },
hotel: { icon: '🏨', color: '#1890ff' },
scenic: { icon: '🏞️', color: '#52c41a' },
shopping: { icon: '🛍️', color: '#eb2f96' },
hospital: { icon: '🏥', color: '#f5222d' },
};
function createCategoryMarker(category, name) {
const { icon, color } = categoryIcons[category] || { icon: '📍', color: '#1890ff' };
return new AMap.Marker({
position: [116.397, 39.909],
content: `
<div class="category-marker" style="--marker-color: color">
<div class="marker-icon">icon</div>
<div class="marker-label">name</div>
<div class="marker-arrow"></div>
</div>
`,
offset: new AMap.Pixel(-50, -58),
});
}
// 使用示例
const restaurantMarker = createCategoryMarker('restaurant', '海底捞火锅');
```
```css
.category-marker {
display: flex;
flex-direction: column;
align-items: center;
}
.marker-icon {
width: 36px;
height: 36px;
background: var(--marker-color);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
border: 2px solid #fff;
}
.marker-label {
margin-top: 4px;
padding: 2px 8px;
background: #fff;
border-radius: 4px;
font-size: 12px;
color: #333;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
white-space: nowrap;
max-width: 100px;
overflow: hidden;
text-overflow: ellipsis;
}
.marker-arrow {
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid #fff;
}
```
## 2. 带文字标记
```javascript
const marker = new AMap.Marker({
position: [116.397, 39.909],
label: {
content: '北京天安门',
direction: 'top', // top, right, bottom, left, center
offset: new AMap.Pixel(0, -5),
},
});
```
## 2. 海量标注 (LabelMarker)
**强烈推荐**用于海量点位(千级/万级以上)展示。它是基于 WebGL 的矢量标注,支持文字和图标避让,性能极佳。
> **注意**:必须配合 `LabelsLayer` 图层使用。
```javascript
// 1. 创建图层
const layer = new AMap.LabelsLayer({
zooms: [3, 20],
zIndex: 1000,
collision: true, // 开启碰撞避让
allowCollision: false, // 允许被避让隐藏
});
map.add(layer);
// 2. 创建 LabelMarker
const labelMarker = new AMap.LabelMarker({
position: [116.397, 39.909],
icon: {
type: 'image',
image: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png',
size: [6, 10],
anchor: 'bottom-center',
},
text: {
content: '北京天安门',
direction: 'top',
style: {
fontSize: 12,
fillColor: '#fff',
strokeColor: '#000',
strokeWidth: 1,
}
}
});
// 3. 添加到图层
layer.add(labelMarker);
```
## 3. 灵活点标记 (ElasticMarker)
适用于随地图缩放需要动态改变样式或大小的场景。
```javascript
const elasticMarker = new AMap.ElasticMarker({
position: [116.397, 39.909],
zooms: [14, 20],
styles: [{
icon: {
img: '...',
size: [16, 16],
ancher: [8, 16],
fitZoom: 14, // 适用于 zoom >= 14
scaleFactor: 2, // 缩放比例
}
}]
});
map.add(elasticMarker);
```
## 常用操作
```javascript
marker.setPosition([lng, lat]); // 更新位置
marker.setMap(null); // 从地图移除
marker.hide(); // 隐藏
marker.show(); // 显示
```
FILE:references/routing.md
# 路径规划 (Routing)
高德地图提供了驾车、步行、骑行和公交等多种路径规划服务。
## 1. 驾车路线规划 (Driving)
支持策略配置(如躲避拥堵、不走高速等)和多点路径规划。
```javascript
// 构造路线规划类
const driving = new AMap.Driving({
map: map, // 绑定地图,自动绘制路线
panel: 'panel-id', // 结果列表的容器 ID (可选)
policy: AMap.DrivingPolicy.LEAST_TIME, // 策略:最快
});
// 根据经纬度规划
// 参数:起点,终点,(可选)途经点,回调
driving.search(
[116.379028, 39.865042], // 起点
[116.427281, 39.903719], // 终点
function(status, result) {
if (status === 'complete') {
console.log('绘制驾车路线完成');
} else {
console.error('获取驾车数据失败:' + result);
}
}
);
// 根据关键字规划
driving.search([
{keyword: '北京站', city: '北京'},
{keyword: '北京大学', city: '北京'}
], function(status, result) {
// ...
});
// 根据关键字规划
driving.search([
{keyword: '北京站', city: '北京'},
{keyword: '北京大学', city: '北京'}
], function(status, result) {
// ...
});
```
## 完整示例
```javascript
const map = new AMap.Map('container', {
zoom: 12,
center: [116.397, 39.909]
});
const driving = new AMap.Driving({
policy: AMap.DrivingPolicy.LEAST_TIME,
showTraffic: true
});
function planDriving(start, end) {
// 清除之前的路线
driving.clear();
driving.search(start, end, function(status, result) {
if (status === 'complete') {
const route = result.routes[0];
// 提取路径点
const path = [];
route.steps.forEach(step => {
path.push(...step.path);
});
// 绘制路线
const polyline = new AMap.Polyline({
path: path,
strokeColor: '#1890ff',
strokeWeight: 6,
strokeOpacity: 0.9,
lineJoin: 'round',
lineCap: 'round'
});
map.add(polyline);
// 显示信息
showRouteInfo(route);
// 调整视野
map.setFitView();
} else {
alert('驾车规划失败:' + result);
}
});
}
function showRouteInfo(route) {
const distance = (route.distance / 1000).toFixed(1) + ' 公里';
const time = formatTime(route.time);
const tolls = route.tolls ? route.tolls + ' 元' : '无';
console.log(`距离: distance, 时间: time, 过路费: tolls`);
}
function formatTime(seconds) {
const hours = Math.floor(seconds / 3600);
const minutes = Math.round((seconds % 3600) / 60);
if (hours > 0) {
return `hours 小时 minutes 分钟`;
}
return `minutes 分钟`;
}
// 使用
planDriving([116.379028, 39.865042], [116.427281, 39.903719]);
```
## 自定义路线样式
```javascript
driving.search(start, end, function(status, result) {
if (status === 'complete') {
const route = result.routes[0];
const path = [];
route.steps.forEach(step => {
path.push(...step.path);
});
// 底层阴影
const shadowLine = new AMap.Polyline({
path: path,
strokeColor: '#0d47a1',
strokeWeight: 10,
strokeOpacity: 0.5
});
// 主路线
const mainLine = new AMap.Polyline({
path: path,
strokeColor: '#1890ff',
strokeWeight: 6,
strokeOpacity: 0.9
});
map.add([shadowLine, mainLine]);
}
});
```
## 清除路线
```javascript
// 使用内置方法
driving.clear();
// 或手动移除
map.remove(polyline);
```
## 注意事项
1. **起终点格式**: 支持经纬度数组或关键字对象
2. **途经点限制**: 最多支持 16 个途经点
3. **路况显示**: 设置 `showTraffic: true` 显示实时路况
4. **车牌限行**: 设置 `number` 参数可判断限行路段
5. **自动渲染**: 设置 map 和 panel 后会自动渲染路线和结果面板
## 2. 其他出行方式
接口调用方式与 `Driving` 类似。
### 步行 (Walking)
```javascript
const walking = new AMap.Walking({
map: map,
panel: 'panel'
});
walking.search([116.399028, 39.845042], [116.436281, 39.880719], function(status, result) {});
```
## 完整示例
```javascript
const map = new AMap.Map('container', {
zoom: 14,
center: [116.397, 39.909]
});
const walking = new AMap.Walking();
function planWalking(start, end) {
walking.search(start, end, function(status, result) {
if (status === 'complete') {
const route = result.routes[0];
// 提取路径点
const path = [];
route.steps.forEach(step => {
path.push(...step.path);
});
// 绘制路线(虚线样式)
const polyline = new AMap.Polyline({
path: path,
strokeColor: '#52c41a',
strokeWeight: 5,
strokeOpacity: 0.9,
strokeStyle: 'dashed', // 虚线
strokeDasharray: [10, 5]
});
map.add(polyline);
// 添加起点终点标记
addStartEndMarkers(start, end);
// 显示信息
const distance = formatDistance(route.distance);
const time = formatTime(route.time);
console.log(`步行距离: distance, 预计时间: time`);
// 调整视野
map.setFitView();
} else {
alert('步行规划失败');
}
});
}
function addStartEndMarkers(start, end) {
// 起点
new AMap.Marker({
map: map,
position: start,
content: createMarkerContent('起', '#52c41a'),
offset: new AMap.Pixel(-16, -40)
});
// 终点
new AMap.Marker({
map: map,
position: end,
content: createMarkerContent('终', '#f5222d'),
offset: new AMap.Pixel(-16, -40)
});
}
function createMarkerContent(text, color) {
return `
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="40" viewBox="0 0 32 40">
<path d="M16 0C7.163 0 0 7.163 0 16c0 12 16 24 16 24s16-12 16-24C32 7.163 24.837 0 16 0z" fill="color"/>
<circle cx="16" cy="14" r="6" fill="#fff"/>
<text x="16" y="18" text-anchor="middle" fill="color" font-size="10" font-weight="bold">text</text>
</svg>
`;
}
function formatDistance(distance) {
if (distance < 1000) {
return Math.round(distance) + ' 米';
}
return (distance / 1000).toFixed(1) + ' 公里';
}
function formatTime(seconds) {
if (seconds < 60) {
return Math.round(seconds) + ' 秒';
}
return Math.round(seconds / 60) + ' 分钟';
}
// 使用
planWalking([116.379028, 39.865042], [116.385281, 39.870719]);
```
### 骑行 (Riding)
```javascript
const riding = new AMap.Riding({
map: map
});
riding.search([116.399028, 39.845042], [116.436281, 39.880719]);
```
## 完整示例
```javascript
const map = new AMap.Map('container', {
zoom: 13,
center: [116.397, 39.909]
});
const riding = new AMap.Riding();
function planRiding(start, end) {
riding.search(start, end, function(status, result) {
if (status === 'complete') {
const route = result.routes[0];
// 提取路径点
const path = [];
route.rides.forEach(ride => {
path.push(...ride.path);
});
// 绘制路线(橙色,表示骑行)
const polyline = new AMap.Polyline({
path: path,
strokeColor: '#fa8c16',
strokeWeight: 5,
strokeOpacity: 0.9,
lineJoin: 'round',
lineCap: 'round'
});
map.add(polyline);
// 添加起点终点标记
addStartEndMarkers(start, end);
// 显示信息
showRouteInfo(route);
// 调整视野
map.setFitView();
} else {
alert('骑行规划失败');
}
});
}
function addStartEndMarkers(start, end) {
// 起点
new AMap.Marker({
map: map,
position: start,
content: createBikeMarker('起', '#52c41a'),
offset: new AMap.Pixel(-16, -40)
});
// 终点
new AMap.Marker({
map: map,
position: end,
content: createBikeMarker('终', '#fa541c'),
offset: new AMap.Pixel(-16, -40)
});
}
function createBikeMarker(text, color) {
return `
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="40" viewBox="0 0 32 40">
<path d="M16 0C7.163 0 0 7.163 0 16c0 12 16 24 16 24s16-12 16-24C32 7.163 24.837 0 16 0z" fill="color"/>
<circle cx="16" cy="14" r="6" fill="#fff"/>
<text x="16" y="18" text-anchor="middle" fill="color" font-size="10" font-weight="bold">text</text>
</svg>
`;
}
function showRouteInfo(route) {
const distance = formatDistance(route.distance);
const time = formatTime(route.time);
// 估算消耗卡路里(约 30 卡/公里)
const calories = Math.round(route.distance / 1000 * 30);
console.log(`
骑行距离: distance
预计时间: time
预计消耗: calories 卡路里
`);
}
function formatDistance(distance) {
if (distance < 1000) {
return Math.round(distance) + ' 米';
}
return (distance / 1000).toFixed(1) + ' 公里';
}
function formatTime(seconds) {
const hours = Math.floor(seconds / 3600);
const minutes = Math.round((seconds % 3600) / 60);
if (hours > 0) {
return `hours 小时 minutes 分钟`;
}
return `minutes 分钟`;
}
// 使用
planRiding([116.379028, 39.865042], [116.420281, 39.890719]);
```
## 自定义路线样式
```javascript
// 橙色渐变效果(骑行风格)
const colors = ['#fa8c16', '#ffa940', '#ffc069'];
riding.search(start, end, function(status, result) {
if (status === 'complete') {
const route = result.routes[0];
const path = [];
route.rides.forEach(ride => {
path.push(...ride.path);
});
// 底层阴影
const shadowLine = new AMap.Polyline({
path: path,
strokeColor: '#d46b08',
strokeWeight: 8,
strokeOpacity: 0.4
});
// 主路线
const mainLine = new AMap.Polyline({
path: path,
strokeColor: '#fa8c16',
strokeWeight: 5,
strokeOpacity: 0.9,
lineJoin: 'round',
lineCap: 'round'
});
map.add([shadowLine, mainLine]);
}
});
```
## 电动车模式
```javascript
const riding = new AMap.Riding({
policy: 1 // 1 表示电动车
});
riding.search(start, end, function(status, result) {
// 电动车路线规划
});
```
## 清除路线
```javascript
riding.clear();
```
## 注意事项
1. **路径特点**: 骑行路线会优先选择非机动车道、自行车道
2. **速度估算**: 默认按照 15km/h(普通自行车)或 20km/h(电动车)估算
3. **距离限制**: 骑行规划适合中短距离,过长距离可能无结果
4. **颜色区分**: 建议使用橙色与驾车(蓝色)、步行(绿色)路线区分
5. **上下坡**: 骑行路线会尽量避免陡坡路段
### 公交 (Transfer)
```javascript
const transfer = new AMap.Transfer({
map: map,
city: '北京市',
policy: AMap.TransferPolicy.LEAST_TIME // 最快捷模式
});
transfer.search([116.291, 39.887], [116.436, 39.880], function(status, result) {});
```
## 完整示例
```javascript
const map = new AMap.Map('container', {
zoom: 12,
center: [116.397, 39.909]
});
const transfer = new AMap.Transfer({
city: '北京市',
policy: AMap.TransferPolicy.LEAST_TIME
});
function planTransit(start, end) {
transfer.search(start, end, function(status, result) {
if (status === 'complete' && result.plans && result.plans.length > 0) {
const plan = result.plans[0]; // 取第一个方案
// 遍历每个段落
plan.segments.forEach((segment, index) => {
// 乘车段
if (segment.transit && segment.transit.path) {
const polyline = new AMap.Polyline({
path: segment.transit.path,
strokeColor: '#1890ff',
strokeWeight: 6,
strokeOpacity: 0.9
});
map.add(polyline);
// 添加上下车站标记
addStationMarker(segment.transit.on_station, '上');
addStationMarker(segment.transit.off_station, '下');
}
// 步行段
if (segment.walking && segment.walking.path) {
const polyline = new AMap.Polyline({
path: segment.walking.path,
strokeColor: '#52c41a',
strokeWeight: 4,
strokeOpacity: 0.8,
strokeStyle: 'dashed'
});
map.add(polyline);
}
});
// 显示方案信息
showPlanInfo(plan);
// 调整视野
map.setFitView();
} else {
alert('公交规划失败');
}
});
}
function addStationMarker(station, type) {
if (!station) return;
new AMap.Marker({
map: map,
position: station.location,
content: `<div style="
background: '#fa541c';
color: #fff;
padding: 2px 6px;
border-radius: 4px;
font-size: 12px;
">type station.name</div>`,
offset: new AMap.Pixel(-20, -10)
});
}
function showPlanInfo(plan) {
const distance = formatDistance(plan.distance);
const time = formatTime(plan.time);
const cost = plan.cost ? plan.cost + ' 元' : '未知';
const walkDistance = formatDistance(plan.walking_distance);
console.log(`
总距离: distance
预计时间: time
票价: cost
步行距离: walkDistance
`);
// 显示换乘详情
plan.segments.forEach((segment, index) => {
if (segment.transit) {
const t = segment.transit;
console.log(`第index + 1段: t.name (t.on_station.name → t.off_station.name)`);
}
});
}
function formatDistance(distance) {
if (distance < 1000) {
return Math.round(distance) + ' 米';
}
return (distance / 1000).toFixed(1) + ' 公里';
}
function formatTime(seconds) {
const hours = Math.floor(seconds / 3600);
const minutes = Math.round((seconds % 3600) / 60);
if (hours > 0) {
return `hours 小时 minutes 分钟`;
}
return `minutes 分钟`;
}
// 使用
planTransit([116.379028, 39.865042], [116.527281, 39.950719]);
```
## 显示多个方案
```javascript
transfer.search(start, end, function(status, result) {
if (status === 'complete' && result.plans) {
// 显示所有方案供用户选择
result.plans.forEach((plan, index) => {
const info = {
index: index + 1,
time: formatTime(plan.time),
cost: plan.cost + ' 元',
transfers: plan.segments.filter(s => s.transit).length - 1 // 换乘次数
};
console.log(`方案info.index: info.time, info.cost, 换乘info.transfers次`);
});
}
});
```
## 清除路线
```javascript
transfer.clear();
```
## 注意事项
1. **城市参数必填**: Transfer 必须指定城市参数
2. **跨城市**: 不支持跨城市公交规划
3. **换乘策略**: 不同策略会返回不同的方案
4. **夜班车**: 设置 `nightflag: true` 计算夜班车路线
5. **多方案**: 通常会返回多个方案,可供用户选择
6. **路径绘制**: 需要分别处理乘车段和步行段
## 3. 拖拽导航
开启 `showTraffic` 可显示实时路况,部分插件支持拖拽修改路径。
```javascript
const driving = new AMap.Driving({
map: map,
showTraffic: true, // 显示路况
});
```
FILE:references/search.md
# 搜索服务 (Search)
搜索服务主要包含 POI 搜索 (`PlaceSearch`) 和 输入提示 (`AutoComplete`)。
## 1. 输入提示 (AutoComplete)
根据输入关键字提示匹配信息,通常与搜索组合使用。
```javascript
const autoOptions = {
city: '北京', // 限制城市
input: 'tipinput' // 绑定输入框的 ID,自动监听输入
};
const autoComplete = new AMap.AutoComplete(autoOptions);
// 监听选中事件
autoComplete.on('select', function(e) {
console.log('选中:', e.poi.name);
// 选中后通常调用 PlaceSearch 进行详细搜索
placeSearch.search(e.poi.name);
});
```
## 2. POI 搜索 (PlaceSearch)
查询兴趣点(POI)信息,如餐厅、酒店、景点等。
### 基础配置
```javascript
const placeSearch = new AMap.PlaceSearch({
map: map, // 结果自动展示在地图上
panel: 'panel', // 结果列表容器
pageSize: 5, // 每页结果数
pageIndex: 1, // 当前页码
city: '010', // 兴趣点城市
citylimit: true, // 是否强制限制在设置的城市内
});
```
### 搜索方式
#### 关键字搜索
```javascript
placeSearch.search('北京大学', function(status, result) {
// result.poiList.pois 包含 POI 数组
});
```
#### 周边搜索 (NearBy)
查询中心点周边的 POI。
```javascript
const center = [116.405467, 39.907761];
const radius = 500; // 半径 (米)
const type = '餐饮服务'; // POI 类型
placeSearch.searchNearBy(type, center, radius, function(status, result) {
// ...
});
```
#### 多边形内搜索 (InBounds)
查询矩形或多边形范围内的 POI。
```javascript
const polygon = new AMap.Polygon({
path: [[116.39, 39.91], [116.41, 39.91], [116.41, 39.93], [116.39, 39.93]]
});
placeSearch.searchInBounds('酒店', polygon, function(status, result) {
// ...
});
```
## POI 类型编码
常用类型编码示例:
| 编码 | 类型 |
| :--- | :--- |
| 050000 | 餐饮服务 |
| 060000 | 购物服务 |
| 070000 | 生活服务 |
| 080000 | 体育休闲服务 |
| 090000 | 医疗保健服务 |
| 100000 | 住宿服务 |
| 110000 | 风景名胜 |
| 120000 | 商务住宅 |
| 130000 | 政府机构及社会团体 |
| 140000 | 科教文化服务 |
| 150000 | 交通设施服务 |
| 160000 | 金融保险服务 |
## 注意事项
1. **城市设置**: 不设置 city 时默认全国搜索
2. **结果数量**: pageSize 最大为 50
3. **详细信息**: 需要电话、网址等信息时设置 `extensions: 'all'`
4. **距离字段**: 只有周边搜索时才有 distance 字段
5. **自动渲染**: 设置 map 和 panel 后会自动渲染结果,无需手动处理
FILE:references/security.md
# 安全配置 (Security Configuration)
自 2021 年 12 月 02 日起,高德地图 JSAPI v2.0 强制要求进行安全密钥配置,否则将无法正常加载地图或调用插件。
## 配置原理
为了提升密钥安全性,JSAPI v2.0 引入了“安全密钥”机制。开发者需要配合 `key` (用户 Key) 和 `securityJsCode` (安全密钥) 使用。
- **Key (用户 Key)**:用于标识开发者身份,明文传递。
- **SecurityJsCode (安全密钥)**: 用于后端验证,不应在生产环境前端明文暴露。
## 配置方式
### 方式一:通过环境变量设置(开发环境推荐)
在开发阶段,建议通过环境变量 `AMAP_SECURITY_JS_CODE` 传入安全密钥,避免在代码中硬编码敏感信息。
**注意:请确保在调用 `AMapLoader.load` 之前设置。**
> **安全警告**:禁止在代码中硬编码安全密钥,也不要将密钥提交到版本控制系统。请始终通过环境变量或后端代理的方式安全传递密钥。
```javascript
window._AMapSecurityConfig = {
securityJsCode: process.env.AMAP_SECURITY_JS_CODE, // 通过环境变量安全获取
};
```
### 方式二:代理转发(生产环境推荐)
在生产环境中,为了避免安全密钥泄露,强烈建议使用代理服务器转发请求。通过配置 `serviceHost`,将地图 API 请求转发到您的后端服务,再由后端服务附带安全密钥请求高德接口。
#### 1. 前端配置
设置 `serviceHost` 指向您的代理服务地址。
```javascript
window._AMapSecurityConfig = {
serviceHost: 'https://您的代理服务器域名/_AMapService',
// 例如:'https://api.example.com/_AMapService'
};
```
#### 2. Nginx 代理配置示例
在您的 Nginx 服务器上配置转发规则。
```nginx
server {
listen 80;
server_name api.example.com;
location /_AMapService/ {
set $args "$args&jscode=您的安全密钥";
proxy_pass https://restapi.amap.com/;
}
}
```
**配置说明:**
- 前端请求 `https://api.example.com/_AMapService/v3/weather/weatherInfo?city=110101`
- Nginx 转发为 `https://restapi.amap.com/v3/weather/weatherInfo?city=110101&jscode=您的安全密钥`
#### 3. Node.js 代理配置示例
使用 `express` 和 `http-proxy-middleware` 实现代理转发。
```javascript
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
app.use('/_AMapService', createProxyMiddleware({
target: 'https://restapi.amap.com',
changeOrigin: true,
pathRewrite: { '^/_AMapService': '' }, // 去除请求路径中的 /_AMapService 前缀
onProxyReq: (proxyReq, req, res) => {
// 拦截请求,追加 jscode 参数
const url = new URL(req.url, 'https://restapi.amap.com');
url.searchParams.append('jscode', '您的安全密钥');
// 修改转发请求的路径
proxyReq.path = url.pathname + url.search;
}
}));
app.listen(3000, () => {
console.log('Proxy server is running on http://localhost:3000');
});
```
#### 4. Java (Spring Boot) 代理配置示例
使用 `RestTemplate` 手动转发请求并追加安全密钥。
```java
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.ResponseEntity;
import javax.servlet.http.HttpServletRequest;
@RestController
public class AMapProxyController {
// 建议将密钥配置在 application.properties 中
private static final String SECURITY_JS_CODE = "您的安全密钥";
@GetMapping("/_AMapService/**")
public ResponseEntity<String> proxy(HttpServletRequest request) {
// 1. 解析目标路径,去除本地代理前缀
String targetPath = request.getRequestURI().replace("/_AMapService", "");
String amapUrl = "https://restapi.amap.com" + targetPath;
// 2. 组装查询参数,追加 jscode
String queryString = request.getQueryString();
if (queryString == null || queryString.isEmpty()) {
queryString = "jscode=" + SECURITY_JS_CODE;
} else {
queryString += "&jscode=" + SECURITY_JS_CODE;
}
// 3. 发起转发请求
String finalUrl = amapUrl + "?" + queryString;
RestTemplate restTemplate = new RestTemplate();
// 注意:此处直接返回字符串,实际生产中可能需要处理 Headers 和状态码的透传
return restTemplate.getForEntity(finalUrl, String.class);
}
}
```
---
## 获取密钥
1. 登录 [高德开放平台控制台](https://console.amap.com/)
2. 进入「应用管理」→「我的应用」
3. 创建应用或选择已有应用
4. 添加 Key,选择「Web端(JS API)」
5. 获取 Key 和对应的安全密钥
## 常见问题
### 1. 地图白屏或提示 INVALID_USER_KEY
- 检查 Key 和安全密钥是否匹配
- 确认 `window._AMapSecurityConfig` 在 JSAPI 加载前已定义
- 检查 Key 是否已启用
### 2. 配额超限
- 登录控制台查看配额使用情况
- 生产环境务必使用代理方式,避免密钥被盗用
### 3. 部分服务不可用
- 确认插件已在 URL 或 Loader 中声明
- 检查 Key 是否有对应服务的使用权限
## 安全最佳实践
1. **开发环境与生产环境分离**: 使用不同的 Key
2. **生产环境必须使用代理**: 避免前端暴露安全密钥
3. **设置 IP 白名单**: 在控制台配置允许访问的服务器 IP
4. **定期更换密钥**: 如有泄露风险,及时重新生成
5. **监控配额使用**: 设置告警,防止异常调用
FILE:references/vector-graphics.md
# 矢量图形 (Vector Graphics)
JSAPI v2.0 支持在地图上绘制各种矢量图形,如折线、多边形、圆和贝塞尔曲线。所有矢量图形均支持 WebGL 渲染。
## 1. 折线 (Polyline)
用于绘制路径、轨迹或边界线。
```javascript
const path = [
[116.368904, 39.913423],
[116.382122, 39.901176],
[116.387271, 39.912501],
[116.398258, 39.904600]
];
const polyline = new AMap.Polyline({
path: path,
isOutline: true, // 是否显示描边
outlineColor: '#ffeeff', // 描边颜色
borderWeight: 3, // 描边宽度
strokeColor: "#3366FF", // 线颜色
strokeOpacity: 1, // 线透明度
strokeWeight: 6, // 线宽
strokeStyle: "solid", // 线样式: solid, dashed
strokeDasharray: [10, 5], // 虚线间隔
lineJoin: 'round', // 折线拐点样式
lineCap: 'round', // 折线端点样式
zIndex: 50,
});
map.add(polyline);
```
### Polyline 配置项
| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| path | Array | - | 路径坐标 `[[lng, lat], ...]` |
| strokeColor | String | '#00D' | 线条颜色 |
| strokeOpacity | Number | 1 | 线条透明度 0-1 |
| strokeWeight | Number | 1 | 线条宽度(像素) |
| strokeStyle | String | 'solid' | 线条样式:solid / dashed |
| strokeDasharray | Array | - | 虚线间隔,如 `[10, 5]` |
| isOutline | Boolean | false | 是否显示描边 |
| outlineColor | String | '#000' | 描边颜色 |
| borderWeight | Number | 1 | 描边宽度 |
| lineJoin | String | 'miter' | 拐点样式:miter / round / bevel |
| lineCap | String | 'butt' | 端点样式:butt / round / square |
| geodesic | Boolean | false | 是否大地线(地球曲面最短路径) |
| showDir | Boolean | false | 是否显示方向箭头 |
| zIndex | Number | 10 | 层叠顺序 |
| extData | Any | - | 自定义数据 |
## 2. 多边形 (Polygon)
用于绘制区域、围栏或建筑物轮廓。
```javascript
const polygonPath = [
[116.403322, 39.920255],
[116.410703, 39.897555],
[116.402292, 39.892353],
[116.389846, 39.891365]
];
const polygon = new AMap.Polygon({
path: polygonPath,
fillColor: '#ccebc5', // 填充颜色
fillOpacity: 0.5, // 填充透明度
strokeColor: '#2b8cbe', // 轮廓线颜色
strokeWeight: 2, // 轮廓线宽度
});
map.add(polygon);
```
### Polygon 配置项
| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| path | Array | - | 多边形路径 `[[lng, lat], ...]`,支持带孔 `[外环, 孔1, 孔2]` |
| fillColor | String | '#00D' | 填充颜色 |
| fillOpacity | Number | 0.5 | 填充透明度 0-1 |
| strokeColor | String | '#00D' | 边框颜色 |
| strokeOpacity | Number | 1 | 边框透明度 0-1 |
| strokeWeight | Number | 1 | 边框宽度(像素) |
| strokeStyle | String | 'solid' | 边框样式:solid / dashed |
| strokeDasharray | Array | - | 虚线间隔 |
| zIndex | Number | 10 | 层叠顺序 |
| extData | Any | - | 自定义数据 |
## 3. 圆 (Circle)
用于绘制圆形区域,常用于周边搜索范围展示。
```javascript
const circle = new AMap.Circle({
center: [116.403322, 39.920255], // 圆心
radius: 1000, // 半径 (米)
fillColor: '#ee2200',
fillOpacity: 0.5,
strokeColor: '#F33',
strokeWeight: 1,
});
map.add(circle);
```
## 4. 贝塞尔曲线 (BezierCurve)
绘制平滑曲线,常用于航线或流向图。
```javascript
const path = [
// 起点
[116.39, 39.91, 116.37, 39.91], // 控制点1, 控制点2
// 途经点
[116.38, 39.92, 116.38, 39.93, 116.39, 39.93],
// ...
];
const bezier = new AMap.BezierCurve({
path: path,
isOutline: true,
outlineColor: '#ffeeff',
borderWeight: 3,
strokeColor: "#3366FF",
strokeWeight: 6,
strokeOpacity: 0.9,
});
map.add(bezier);
```
## 矢量图形编辑器
高德提供了 `AMap.PolyEditor`, `AMap.CircleEditor` 等插件,允许用户在地图上交互式编辑矢量图形。
```javascript
// 需先加载插件 AMap.PolyEditor
const polyEditor = new AMap.PolyEditor(map, polyline);
polyEditor.open(); // 开启编辑
// polyEditor.close(); // 结束编辑
polyEditor.on('end', function(event) {
console.log('编辑结束,新路径:', event.target.getPath());
});
```
## 5. 最佳实践
### 性能优化
```javascript
// 大量坐标点时,使用 setPath 而非重新创建
polyline.setPath(newPath); // 推荐
// map.remove(old); map.add(new); // 不推荐
// 批量操作使用数组
map.add([polyline1, polyline2, polygon1]);
map.remove([polyline1, polyline2]);
```
### 常见问题
**Q: 多边形不显示?**
检查路径是否闭合(首尾相连),确保至少 3 个点。
**Q: 编辑器报错?**
确保先加载插件:
```javascript
AMap.plugin(['AMap.PolyEditor', 'AMap.CircleEditor'], function() {
// 使用编辑器
});
```
**Q: 如何判断点是否在多边形内?**
```javascript
const isInside = polygon.contains([lng, lat]);
```
FILE:references/view-control.md
# 视图控制 (View Control)
高德地图 JSAPI v2.0 提供了强大的 3D 视图控制能力,包括缩放、旋转、俯仰和中心点移动。
## 核心属性
在地图初始化或运行时,可以通过以下属性控制视口:
- **zoom**: 缩放级别 (2 - 20)。
- **center**: 地图中心点 `[lng, lat]`。
- **rotation**: 旋转角度 (0 - 360),顺时针。
- **pitch**: 俯仰角度 (0 - 83),0 为垂直向下,83 为接近水平。
## 常用方法
### 1. 缩放 (Zoom)
```javascript
map.setZoom(15); // 设置特定级别
map.zoomIn(); // 放大一级
map.zoomOut(); // 缩小一级
const zoom = map.getZoom(); // 获取当前级别
```
### 2. 移动与平移 (Move/Pan)
```javascript
// 瞬间移动到指定位置
map.setCenter([116.40, 39.90]);
// 平滑移动到指定位置 (带动画)
map.panTo([116.40, 39.90]);
// 同时设置缩放和中心点
map.setZoomAndCenter(14, [116.40, 39.90]);
```
### 3. 3D 控制 (Pitch/Rotation)
```javascript
map.setPitch(45); // 设置俯仰角
map.setRotation(90); // 设置旋转角 (正北为0,顺时针)
```
### 4. 限制显示范围 (Bounds)
限制用户只能在特定区域内浏览地图。
```javascript
const bounds = new AMap.Bounds(
[116.0, 39.0], // 西南角
[117.0, 40.0] // 东北角
);
map.setLimitBounds(bounds);
// 清除限制
map.clearLimitBounds();
```
## 视图自适应
让地图自动调整层级和中心,以显示所有指定的覆盖物。
```javascript
// 自动适配视口
map.setFitView(
[marker1, polygon1], // 覆盖物数组,为空则包含所有
false, // 是否立即过渡 (false 为动画)
[60, 60, 60, 60] // 上下左右的 padding
);
```
## 注意事项
- 容器高度:确保地图容器 div 在 CSS 中有明确的宽度和高度,否则地图无法显示。
- 坐标系:高德地图使用 GCJ-02 坐标系(火星坐标系)。
- 插件加载:可以在 AMapLoader.load 时一次性引入,也可以在使用时通过 AMap.plugin(['AMap.XX'], callback) 动态引入。
- 性能优化:对于 1000 个以上的点标记,强烈建议使用 AMap.LabelMarker 或 AMap.MassMarks 而非普通 AMap.Marker。
- references/map-init.md
- references/security.md
### 说明:
1. **安全配置模块**:在 v2.0 中,这是最常见的报错来源。我在 `0. 安全配置` 中特别强调了 `window._AMapSecurityConfig`。
2. **Loader 模式**:官方现在推荐使用异步 Loader 模式,示例代码直接给出了 `AMapLoader` 的写法。
3. **高性能组件**:针对 v2.0 增加了 `LabelMarker` 的引用,这是 WebGL 版本相比 v1.4 的核心优势。
4. **结构化引用**:保持了与你提供的百度地图 Skill 一致的 `references/*.md` 结构,方便 LLM 模拟读取详细文档。