@maptec/cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +284 -0
- package/bin/maptec.js +2 -0
- package/dist/chunk-K574OFFK.js +122 -0
- package/dist/chunk-K574OFFK.js.map +1 -0
- package/dist/cli.js +899 -0
- package/dist/cli.js.map +1 -0
- package/dist/store-ZU7HLXCV.js +18 -0
- package/dist/store-ZU7HLXCV.js.map +1 -0
- package/package.json +47 -0
- package/skills/README.md +30 -0
- package/skills/jsapi-skills/README.md +60 -0
- package/skills/jsapi-skills/SKILL.md +145 -0
- package/skills/jsapi-skills/package.json +31 -0
- package/skills/jsapi-skills/references/controls.md +195 -0
- package/skills/jsapi-skills/references/events.md +222 -0
- package/skills/jsapi-skills/references/geocoding.md +184 -0
- package/skills/jsapi-skills/references/map-style.md +123 -0
- package/skills/jsapi-skills/references/map.md +154 -0
- package/skills/jsapi-skills/references/marker.md +136 -0
- package/skills/jsapi-skills/references/operate.md +138 -0
- package/skills/jsapi-skills/references/overlay.md +311 -0
- package/skills/jsapi-skills/references/place-search.md +411 -0
- package/skills/jsapi-skills/references/poi-categories.md +123 -0
- package/skills/jsapi-skills/references/popup.md +146 -0
- package/skills/jsapi-skills/references/re-geocoding.md +183 -0
- package/skills/jsapi-skills/references/routing.md +347 -0
- package/skills/jsapi-skills/references/track.md +240 -0
- package/skills/jsapi-skills/scripts/validate_jsapi_skill.py +160 -0
- package/skills/webapi-skills/README.md +73 -0
- package/skills/webapi-skills/SKILL.md +63 -0
- package/skills/webapi-skills/package.json +32 -0
- package/skills/webapi-skills/references/direction-api.md +175 -0
- package/skills/webapi-skills/references/geocoding.md +195 -0
- package/skills/webapi-skills/references/ip-location.md +87 -0
- package/skills/webapi-skills/references/matrix-api.md +149 -0
- package/skills/webapi-skills/references/nearby-search.md +223 -0
- package/skills/webapi-skills/references/places.md +239 -0
- package/skills/webapi-skills/references/quick-start-cn.md +219 -0
- package/skills/webapi-skills/references/reverse-geocoding.md +157 -0
- package/skills/webapi-skills/references/suggest.md +111 -0
- package/skills/webapi-skills/references/text-search.md +282 -0
- package/skills/webapi-skills/scripts/validate_webapi_skill.py +158 -0
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
# Maptec PlaceSearch Reference
|
|
2
|
+
|
|
3
|
+
本文件对应功能 **POI检索**:面向 POI 检索场景,支持关键词检索、周边检索、类型检索、详情检索。
|
|
4
|
+
|
|
5
|
+
| 用户需求 | 优先实现 |
|
|
6
|
+
|---|---|
|
|
7
|
+
| “搜索新加坡所有咖啡馆并标注在地图上” | `PlaceSearch.search`,`keyword`/`type: "Cafe"`,分页,Marker 渲染 |
|
|
8
|
+
| “乌节路附近的餐厅” | 先地理编码乌节路,再 `searchNearby`,`types: "Restaurant"` |
|
|
9
|
+
| “搜索某个地点详情” | 先搜索获得 `placeId`,再详情检索 |
|
|
10
|
+
| “搜索框输入建议” | `suggest` / autocomplete 能力 |
|
|
11
|
+
|
|
12
|
+
## 检索功能与适用场景
|
|
13
|
+
|
|
14
|
+
| 功能 | 适用场景 |
|
|
15
|
+
|---|---|
|
|
16
|
+
| 关键词检索 | 用户输入明确地点名、品牌名、商户名或自然语言关键词时使用,例如“搜索 Starbucks”“搜索新加坡国立大学”。 |
|
|
17
|
+
| 类型检索 | 用户按 POI 类别查找地点时使用,例如“搜索咖啡馆”“搜索新加坡所有餐厅”。需要传入最接近的 `type`,并按分页获取更多结果。 |
|
|
18
|
+
| 周边检索 | 用户要求“附近”“周边”“指定半径内”地点时使用,例如“乌节路附近的餐厅”“当前位置 3 公里内的酒店”。必须提供 `locationLimit.center`,可配置 `radius` 和 `types`。 |
|
|
19
|
+
| 详情检索 | 已获得 `placeId` 后,需要查询地点详情时使用,例如展示电话、地址、营业时间、照片、摘要等更完整信息。 |
|
|
20
|
+
|
|
21
|
+
## When To Use Which Search
|
|
22
|
+
|
|
23
|
+
| User scenario | Use | Required parameters |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| "Search Starbucks", "标记新加坡国立大学" | Text search | `keyword`, `region` |
|
|
26
|
+
| "Show restaurants in Thailand", "泰国所有餐厅" | Type search | `keyword`, `region`, `type` |
|
|
27
|
+
| "Restaurants near me", "周边 3km 餐厅" | Nearby search | `locationLimit.center`, `locationLimit.radius`, optional `types`, `region` |
|
|
28
|
+
| "POIs inside this area" | Bounded/range search | `keyword`, `region`, `locationLimit` bounds |
|
|
29
|
+
| "All / as many as possible" | Search plus pagination | `nextPageToken`, `pageToken`, `pageSize`, max pages |
|
|
30
|
+
| "Search box autocomplete", "搜索框输入建议" | Suggest | `query`, optional `sessionToken`, `types`, `locationBias` |
|
|
31
|
+
| "Show details for this POI", "查看地点详情" | Place details | `placeId`, optional `sessionToken`, `language`, `region` |
|
|
32
|
+
|
|
33
|
+
## Region Selection
|
|
34
|
+
|
|
35
|
+
Use `new Maptec.PlaceSearch({ region })`.
|
|
36
|
+
|
|
37
|
+
Common region codes:
|
|
38
|
+
- Singapore: `sg`
|
|
39
|
+
- Thailand: `th`
|
|
40
|
+
- Japan: `jp`
|
|
41
|
+
- South Korea: `kr`
|
|
42
|
+
- Malaysia: `my`
|
|
43
|
+
- Indonesia: `id`
|
|
44
|
+
- Vietnam: `vn`
|
|
45
|
+
- China: `cn`
|
|
46
|
+
- United States: `us`
|
|
47
|
+
- United Kingdom: `gb`
|
|
48
|
+
|
|
49
|
+
If the user does not specify a location, ask a clarifying question or use the product default only if the product already defines one.
|
|
50
|
+
|
|
51
|
+
## POI Type Mapping
|
|
52
|
+
|
|
53
|
+
Use the closest supported `type` value from `references/poi-categories.md`. Do not invent unsupported values.
|
|
54
|
+
|
|
55
|
+
Important rules:
|
|
56
|
+
|
|
57
|
+
- `search(keyword, options, callback)` uses singular `type`.
|
|
58
|
+
- `searchNearby(options, callback)` uses comma-separated `types`.
|
|
59
|
+
- Do not pass broad natural-language labels as type values. For example, do not use `school`, `restaurant`, `hotel`, `parking`, `cafe`, `tourist_attraction` unless that exact value is confirmed in `poi-categories.md`.
|
|
60
|
+
- If the user gives an exact place name, brand, campus, landmark or address, prefer keyword search without `type`; type filtering can accidentally remove the correct POI.
|
|
61
|
+
- If a type-filtered request returns `ZERO_RESULTS`, retry the same keyword without `type/types`, then report that the category filter was too restrictive.
|
|
62
|
+
|
|
63
|
+
Common mappings:
|
|
64
|
+
|
|
65
|
+
- 大学 / university / college: `College_University`
|
|
66
|
+
- 中学: `Middle_School`
|
|
67
|
+
- 小学: `Primary_School`
|
|
68
|
+
- 幼儿园: `Kindergarten`
|
|
69
|
+
- 培训机构: `Training_Institution`
|
|
70
|
+
- 餐厅 / 餐馆 / restaurant: `Restaurant`
|
|
71
|
+
- 咖啡 / cafe: `Cafe`
|
|
72
|
+
- 酒店 / hotel: `Hotels`、`Star_Rated_Hotel`、`Budget_Hotel_Chain`、`Luxury_Hotel`
|
|
73
|
+
- 停车场 / parking: `Parking`、`Indoor_Parking`、`Outdoor_Parking`、`Roadside_Parking`
|
|
74
|
+
- 加油站 / gas station: `Gas_Station`
|
|
75
|
+
- 充电站 / EV charging: `Ev_Charging_Station`
|
|
76
|
+
- 地铁站 / MRT / subway: `Subway_Light_Rail_Station`
|
|
77
|
+
- 火车站: `Train_Station`
|
|
78
|
+
- 公交站: `Bus_Stop`
|
|
79
|
+
- 机场: `Airport`
|
|
80
|
+
- 医院 / hospital: `General_Hospital`、`Specialized_Hospital`、`Emergency_Center`
|
|
81
|
+
- 诊所 / clinic: `Clinics`、`Private_Clinic`、`Community_Clinic`、`Dental_Clinic`
|
|
82
|
+
- 药房 / pharmacy: `Pharmacy`
|
|
83
|
+
- 银行 / bank: `Bank`
|
|
84
|
+
- ATM: `Atm`
|
|
85
|
+
- 商场 / mall: `Shopping_Mall`、`Shopping_Center`
|
|
86
|
+
- 超市 / supermarket: `Supermarket`
|
|
87
|
+
- 便利店: `Convenience_Store`
|
|
88
|
+
- 景点 / attraction: `Tourism_Culture`、`Historic_Site`、`Observation_Deck`
|
|
89
|
+
- 公园: `Urban_Park`、`National_Park`、`Nature_Reserve`
|
|
90
|
+
- 博物馆: `Museum`
|
|
91
|
+
- 图书馆: `Library`
|
|
92
|
+
- 健身房: `Gym`
|
|
93
|
+
|
|
94
|
+
## Service And Option Types
|
|
95
|
+
|
|
96
|
+
`PlaceSearchOptions` for constructor defaults:
|
|
97
|
+
|
|
98
|
+
- `language?: string`. Default `"en"`.
|
|
99
|
+
- `region?: string`. ccTLD region code.
|
|
100
|
+
- `timeout?: number`. Default `10000`.
|
|
101
|
+
|
|
102
|
+
`PlaceSearchTextOptions` for `search(keyword, options, callback)`:
|
|
103
|
+
|
|
104
|
+
- `language?: string`
|
|
105
|
+
- `region?: string`
|
|
106
|
+
- `type?: string`. Single POI category.
|
|
107
|
+
- `locationBias?: PlaceSearchLocationArea`. Bias results; mutually exclusive with `locationLimit`.
|
|
108
|
+
- `locationLimit?: PlaceSearchLocationArea`. Restrict results; mutually exclusive with `locationBias`.
|
|
109
|
+
- `rank?: "RELEVANCE" | "DISTANCE" | "POPULARITY"`. Default `"POPULARITY"`.
|
|
110
|
+
- `pageSize?: number`. Range `[1, 20]`, default `20`.
|
|
111
|
+
- `pageToken?: string`. Request next page.
|
|
112
|
+
|
|
113
|
+
`PlaceSearchTextResult`:
|
|
114
|
+
|
|
115
|
+
- `status: string`. Typical values include `"OK"`, `"ZERO_RESULTS"`, `"ERROR"`.
|
|
116
|
+
- `places?: PlaceSearchPlace[] | null`.
|
|
117
|
+
- `nextPageToken?: string | null`. Use this as `pageToken` for the next request.
|
|
118
|
+
- `error?: { code: string; message: string } | null`.
|
|
119
|
+
|
|
120
|
+
`PlaceSearchNearbyOptions` for `searchNearby(options, callback)`:
|
|
121
|
+
|
|
122
|
+
- `locationLimit: { center: LngLatLike; radius?: number }`. Required circular search area, radius default `500` meters.
|
|
123
|
+
- `types?: string`. Comma-separated type list, for example `"hotel,restaurant"`.
|
|
124
|
+
- `resultLimit?: number`. Range `[1, 20]`, default `20`.
|
|
125
|
+
- `rank?: "RELEVANCE" | "DISTANCE" | "POPULARITY"`. Default `"DISTANCE"`.
|
|
126
|
+
- `language?: string`
|
|
127
|
+
- `region?: string`
|
|
128
|
+
|
|
129
|
+
`PlaceSearchNearbyResult`:
|
|
130
|
+
|
|
131
|
+
- `status: string`.
|
|
132
|
+
- `places?: PlaceSearchPlace[] | null`.
|
|
133
|
+
- `error?: { code: string; message: string } | null`.
|
|
134
|
+
|
|
135
|
+
`PlaceSearchLocationArea` can be either:
|
|
136
|
+
|
|
137
|
+
- `LngLatBoundsLike`: rectangle, for example `[[103.8, 1.3], [103.9, 1.4]]`.
|
|
138
|
+
- `{ center: LngLatLike; radius: number }`: circle, radius in meters. Radius defaults to `500` meters where the option allows it.
|
|
139
|
+
|
|
140
|
+
`PlaceSearchPlace` common fields:
|
|
141
|
+
|
|
142
|
+
- `id: string`、`name: string`、`displayName: { text: string; languageCode: string }`、`formattedAddress: string`、`location: { latitude: number; longitude: number }`、`types: string[]`、`viewport: { northeast: { latitude: number; longitude: number }; southwest: { latitude: number; longitude: number } }`、`phoneNumber: string`、`openingHours`、`photos`、`summary: { text: string; languageCode: string }`。
|
|
143
|
+
|
|
144
|
+
> **重要**:`location` 是 `{ latitude, longitude }` 对象,直接取值即可。不要把 `location` 写成 `geometry.location`——后者是 Google Maps API 的结构,Maptec 中不存在。
|
|
145
|
+
|
|
146
|
+
Callback types:
|
|
147
|
+
|
|
148
|
+
- `PlaceSearchCallback = (error?, result?) => void`, result type `PlaceSearchTextResult`.
|
|
149
|
+
- `PlaceSearchNearbyCallback = (error?, result?) => void`, result type `PlaceSearchNearbyResult`.
|
|
150
|
+
- `PlaceSearchDetailsCallback = (error?, result?) => void`, result type `PlaceSearchDetailsResult`.
|
|
151
|
+
- `PlaceSearchSuggestCallback = (error?, result?) => void`, result type `PlaceSearchSuggestResult`.
|
|
152
|
+
|
|
153
|
+
## Text Search
|
|
154
|
+
|
|
155
|
+
Use `search(keyword, callback)` or `search(keyword, options, callback)` for keyword/type search.
|
|
156
|
+
|
|
157
|
+
```js
|
|
158
|
+
const placeSearch = new Maptec.PlaceSearch({
|
|
159
|
+
language: "zh-CN",
|
|
160
|
+
region: "sg"
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
placeSearch.search("restaurant", {
|
|
164
|
+
type: "Restaurant",
|
|
165
|
+
region: "sg",
|
|
166
|
+
language: "zh-CN",
|
|
167
|
+
pageSize: 20,
|
|
168
|
+
rank: "POPULARITY"
|
|
169
|
+
}, (error, result) => {
|
|
170
|
+
if (error) return console.error(error);
|
|
171
|
+
const places = result?.places || [];
|
|
172
|
+
console.log(places);
|
|
173
|
+
});
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Use `locationBias` to bias results near an area, and `locationLimit` to restrict results to an area. They are mutually exclusive.
|
|
177
|
+
|
|
178
|
+
```js
|
|
179
|
+
placeSearch.search("hotel", {
|
|
180
|
+
locationBias: {
|
|
181
|
+
center: [103.8198, 1.3521],
|
|
182
|
+
radius: 5000
|
|
183
|
+
},
|
|
184
|
+
rank: "DISTANCE"
|
|
185
|
+
}, callback);
|
|
186
|
+
|
|
187
|
+
placeSearch.search("restaurant", {
|
|
188
|
+
locationLimit: [[103.8, 1.3], [103.9, 1.4]]
|
|
189
|
+
}, callback);
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Type Search Template
|
|
193
|
+
|
|
194
|
+
Use this when the user asks for category results in a region, such as "泰国所有餐厅".
|
|
195
|
+
|
|
196
|
+
```html
|
|
197
|
+
<script>
|
|
198
|
+
Maptec.apiKey = "YOUR_MAPTEC_KEY";
|
|
199
|
+
|
|
200
|
+
const map = new Maptec.Map({
|
|
201
|
+
container: "map",
|
|
202
|
+
style: "https://test-api.maptec.com/maps/v1/styles?style_id=style_00001",
|
|
203
|
+
center: [100.5018, 13.7563],
|
|
204
|
+
zoom: 6
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
map.on("load", () => {
|
|
208
|
+
const search = new Maptec.PlaceSearch({ region: "th" });
|
|
209
|
+
const renderLimit = 80;
|
|
210
|
+
const collectedPlaces = [];
|
|
211
|
+
const renderedKeys = new Set();
|
|
212
|
+
|
|
213
|
+
const toLngLat = (location) => {
|
|
214
|
+
if (!location) return null;
|
|
215
|
+
if (Array.isArray(location)) return location;
|
|
216
|
+
const lng = location.longitude ?? location.lng ?? location.lon;
|
|
217
|
+
const lat = location.latitude ?? location.lat;
|
|
218
|
+
return lng == null || lat == null ? null : [lng, lat];
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const getNextPageToken = (result) =>
|
|
222
|
+
result?.nextPageToken || result?.next_page_token || result?.pageToken || result?.nextToken;
|
|
223
|
+
|
|
224
|
+
const mergeUniquePlaces = (places) => {
|
|
225
|
+
const seen = new Set(collectedPlaces.map((place) => {
|
|
226
|
+
const position = toLngLat(place.location);
|
|
227
|
+
return `${place.id || place.placeId || place.name}:${position?.[0]},${position?.[1]}`;
|
|
228
|
+
}));
|
|
229
|
+
|
|
230
|
+
places.forEach((place) => {
|
|
231
|
+
const position = toLngLat(place.location);
|
|
232
|
+
const key = `${place.id || place.placeId || place.name}:${position?.[0]},${position?.[1]}`;
|
|
233
|
+
if (!seen.has(key)) {
|
|
234
|
+
seen.add(key);
|
|
235
|
+
collectedPlaces.push(place);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
const renderMarkers = () => {
|
|
241
|
+
collectedPlaces.slice(0, renderLimit).forEach((place) => {
|
|
242
|
+
const position = toLngLat(place.location);
|
|
243
|
+
if (!position) return;
|
|
244
|
+
const markerKey = `${place.id || place.placeId || place.name}:${position[0]},${position[1]}`;
|
|
245
|
+
if (renderedKeys.has(markerKey)) return;
|
|
246
|
+
renderedKeys.add(markerKey);
|
|
247
|
+
|
|
248
|
+
const title = place.displayName?.text || place.name || "Unknown place";
|
|
249
|
+
const address = place.formattedAddress || place.address || "";
|
|
250
|
+
const type = place.types?.[0] || "";
|
|
251
|
+
const popup = new Maptec.Popup({
|
|
252
|
+
offset: 25,
|
|
253
|
+
html: `<div style="padding: 5px;">
|
|
254
|
+
<strong style="font-size: 14px;">${title}</strong><br>
|
|
255
|
+
<small style="color: #666;">${address}</small>
|
|
256
|
+
${type ? `<br><small style="color: #999;">${type}</small>` : ""}
|
|
257
|
+
</div>`
|
|
258
|
+
});
|
|
259
|
+
map.addOverlay(new Maptec.Marker({ position, popup }));
|
|
260
|
+
});
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
const loadPage = (pageToken) => {
|
|
264
|
+
const options = pageToken
|
|
265
|
+
? { type: "Restaurant", language: "zh-CN", region: "th", pageSize: 20, pageToken }
|
|
266
|
+
: { type: "Restaurant", language: "zh-CN", region: "th", pageSize: 20 };
|
|
267
|
+
|
|
268
|
+
search.search("餐厅", options, (error, result) => {
|
|
269
|
+
if (error) {
|
|
270
|
+
console.error("PlaceSearch failed", error);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
mergeUniquePlaces(result?.places || []);
|
|
275
|
+
renderMarkers();
|
|
276
|
+
|
|
277
|
+
const nextPageToken = getNextPageToken(result);
|
|
278
|
+
if (nextPageToken && collectedPlaces.length < renderLimit) {
|
|
279
|
+
loadPage(nextPageToken);
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
loadPage();
|
|
285
|
+
});
|
|
286
|
+
</script>
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Nearby Search Template
|
|
290
|
+
|
|
291
|
+
Use this when the user explicitly asks for nearby/radius/range. `searchNearby` receives one options object; it does not receive a keyword as the first argument.
|
|
292
|
+
|
|
293
|
+
```js
|
|
294
|
+
const search = new Maptec.PlaceSearch({ region: "sg" });
|
|
295
|
+
|
|
296
|
+
search.searchNearby({
|
|
297
|
+
locationLimit: {
|
|
298
|
+
center: [103.8198, 1.3521],
|
|
299
|
+
radius: 3000
|
|
300
|
+
},
|
|
301
|
+
types: "restaurant",
|
|
302
|
+
resultLimit: 20,
|
|
303
|
+
language: "zh-CN"
|
|
304
|
+
}, (error, result) => {
|
|
305
|
+
if (error) return console.error(error);
|
|
306
|
+
const places = result?.places || [];
|
|
307
|
+
// Render with Maptec.Marker + Maptec.Popup.
|
|
308
|
+
});
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## Suggest Search
|
|
312
|
+
|
|
313
|
+
Use `suggest(options, callback)` for autocomplete/search-box suggestions. Use the same `sessionToken` for the user typing session and the subsequent detail lookup when applicable.
|
|
314
|
+
|
|
315
|
+
`PlaceSearchSuggestOptions`:
|
|
316
|
+
|
|
317
|
+
- `query: string`.
|
|
318
|
+
- `language?: string`. Default `"en"`.
|
|
319
|
+
- `region?: string`. Default `"SG"` in the SDK docs.
|
|
320
|
+
- `types?: string`. Comma-separated types, for example `"restaurant,cafe"`.
|
|
321
|
+
- `resultLimit?: number`. Range `[1, 20]`, default `20`.
|
|
322
|
+
- `sessionToken?: string`.
|
|
323
|
+
- `locationBias?: PlaceSearchLocationArea`.
|
|
324
|
+
- `locationLimit?: PlaceSearchLocationArea`.
|
|
325
|
+
|
|
326
|
+
`PlaceSearchSuggestResult`:
|
|
327
|
+
|
|
328
|
+
- `status: string`.
|
|
329
|
+
- `suggestions?: PlaceSearchSuggestion[] | null`.
|
|
330
|
+
- `error?: { code: string; message: string } | null`.
|
|
331
|
+
|
|
332
|
+
`PlaceSearchSuggestion`:
|
|
333
|
+
|
|
334
|
+
- `placeId: string`.
|
|
335
|
+
- `placeName: string`.
|
|
336
|
+
- `text?: { languageCode: string; text: string } | null`.
|
|
337
|
+
|
|
338
|
+
```js
|
|
339
|
+
const sessionToken = crypto.randomUUID();
|
|
340
|
+
|
|
341
|
+
placeSearch.suggest({
|
|
342
|
+
query: "rest",
|
|
343
|
+
sessionToken,
|
|
344
|
+
types: "restaurant,cafe",
|
|
345
|
+
resultLimit: 10,
|
|
346
|
+
region: "SG",
|
|
347
|
+
locationBias: {
|
|
348
|
+
center: [103.8198, 1.3521],
|
|
349
|
+
radius: 5000
|
|
350
|
+
}
|
|
351
|
+
}, (error, result) => {
|
|
352
|
+
if (error) return console.error(error);
|
|
353
|
+
const suggestions = result?.suggestions || [];
|
|
354
|
+
console.log(suggestions.map((item) => item.text?.text));
|
|
355
|
+
});
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## Place Details
|
|
359
|
+
|
|
360
|
+
Use `getPlaceDetails(options, callback)` when you already have a `placeId` from `search`, `searchNearby`, or `suggest` and need richer place information.
|
|
361
|
+
|
|
362
|
+
`PlaceSearchDetailsOptions`:
|
|
363
|
+
|
|
364
|
+
- `placeId: string`. Required.
|
|
365
|
+
- `language: string`. Use when you need localized details.
|
|
366
|
+
- `region: string`. Use when you need regional bias/context.
|
|
367
|
+
- `sessionToken: string`. Use the same token from `suggest` when details are selected from autocomplete.
|
|
368
|
+
|
|
369
|
+
`PlaceSearchDetailsResult`:
|
|
370
|
+
|
|
371
|
+
- `status: string`.
|
|
372
|
+
- `places?: PlaceSearchPlace | null`. Details returns a single place object, not an array.
|
|
373
|
+
- `error?: { code: string; message: string } | null`.
|
|
374
|
+
|
|
375
|
+
```js
|
|
376
|
+
placeSearch.getPlaceDetails({
|
|
377
|
+
placeId: "osm-node-10004862482_v0.1",
|
|
378
|
+
sessionToken,
|
|
379
|
+
language: "zh-CN",
|
|
380
|
+
region: "SG"
|
|
381
|
+
}, (error, result) => {
|
|
382
|
+
if (error) return console.error(error);
|
|
383
|
+
const place = result?.places;
|
|
384
|
+
console.log(place?.displayName?.text, place?.formattedAddress, place?.phoneNumber);
|
|
385
|
+
});
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
## Known Pitfalls
|
|
389
|
+
|
|
390
|
+
- **字段名 `places` 而非 `results`**:`PlaceSearchTextResult` 和 `PlaceSearchNearbyResult` 的结果数组字段是 `places`,不是 `results`。不要写成 `result.results`,这是 Google Maps API 的字段名,Maptec 中不存在。
|
|
391
|
+
- **字段名 `location` 而非 `geometry.location`**:`PlaceSearchPlace` 的坐标字段是 `location`,直接包含 `latitude` 和 `longitude` 属性。不要写成 `place.geometry?.location`,这是 Google Maps API 的结构,Maptec 中不存在。正确用法:`place.location.latitude`、`place.location.longitude`,或使用 `toLngLat(place.location)` 辅助函数转为 `[lng, lat]`。
|
|
392
|
+
- A single text search page returns at most `pageSize` results, with documented range `[1, 20]`. Use `nextPageToken` from the result as `pageToken` for broad requests.
|
|
393
|
+
- Nearby search returns at most `resultLimit` results, with documented range `[1, 20]`.
|
|
394
|
+
- `nextPageToken` is for pagination, not for choosing the search type.
|
|
395
|
+
- `type` is what makes text search category/type constrained; `types` is used by nearby search.
|
|
396
|
+
- Do not use `locationBias` for a whole-country category search unless the user asked for biasing near a location.
|
|
397
|
+
- Use `locationLimit` for nearby/radius search and bounded search.
|
|
398
|
+
- Do not pass a keyword to `searchNearby`; nearby search is `searchNearby(options, callback)`.
|
|
399
|
+
- Do not treat details result `places` as an array; `PlaceSearchDetailsResult.places` is a single `PlaceSearchPlace | null`.
|
|
400
|
+
- Keep the same `sessionToken` across `suggest` and `getPlaceDetails` for one autocomplete session when using interactive search.
|
|
401
|
+
- Do not reuse Singapore defaults for Thailand, China, or other regions. The `region`, map center, and zoom must match the user's requested geography.
|
|
402
|
+
- Do not render fake markers for real-world search results. If `PlaceSearch` returns no valid coordinates, show the failure or empty state.
|
|
403
|
+
- If the SDK does not return any pagination token, state that only one page can be rendered from the front end.
|
|
404
|
+
- Keep generated code and actual map rendering logic identical.
|
|
405
|
+
|
|
406
|
+
## Agent 规则
|
|
407
|
+
|
|
408
|
+
- 真实 POI 必须来自 `Maptec.PlaceSearch` 返回结果,不要伪造咖啡馆、餐厅、酒店、地址或坐标。
|
|
409
|
+
- 关键词检索和类型检索使用 `search(keyword, options, callback)`;周边检索使用 `searchNearby(options, callback)`。
|
|
410
|
+
- “全部”“尽可能多”等需求必须说明分页、前端渲染上限和 `nextPageToken` 限制。
|
|
411
|
+
- 结果为空、服务错误、坐标缺失时必须显式处理,不要渲染假 Marker。
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# POI 类目补充
|
|
2
|
+
|
|
3
|
+
当用户要求按类别检索 POI,或者需要填写 `PlaceSearch.search` 的 `type` / `PlaceSearch.searchNearby` 的 `types` 时,使用本参考。
|
|
4
|
+
|
|
5
|
+
## 参数规则
|
|
6
|
+
|
|
7
|
+
- 文本检索:`placeSearch.search(keyword, { type }, callback)`,`type` 为单个类目值。
|
|
8
|
+
- 周边检索:`placeSearch.searchNearby({ locationLimit, types }, callback)`,`types` 为逗号分隔类目值。
|
|
9
|
+
- 类目值必须使用本文件确认的英文枚举,大小写保持一致。
|
|
10
|
+
- 不要使用未确认的通用词作为类型,例如 `school`、`restaurant`、`hotel`、`parking`、`cafe`、`tourist_attraction`。
|
|
11
|
+
- 用户输入明确地点名、品牌、校区、地标或地址时,优先只用关键词检索;不确定类目时不要强塞 `type/types`。
|
|
12
|
+
- 如果带 `type/types` 返回 `ZERO_RESULTS`,应使用同一关键词去掉类型过滤重试。
|
|
13
|
+
|
|
14
|
+
## 常用映射
|
|
15
|
+
|
|
16
|
+
| 用户表达 | 推荐 type/types |
|
|
17
|
+
|---|---|
|
|
18
|
+
| 大学、学院、university、college | `College_University` |
|
|
19
|
+
| 中学 | `Middle_School` |
|
|
20
|
+
| 小学 | `Primary_School` |
|
|
21
|
+
| 幼儿园 | `Kindergarten` |
|
|
22
|
+
| 培训机构 | `Training_Institution` |
|
|
23
|
+
| 餐厅、餐馆、restaurant | `Restaurant` |
|
|
24
|
+
| 咖啡馆、咖啡、cafe | `Cafe` |
|
|
25
|
+
| 酒店、hotel | `Hotels`;细分可用 `Star_Rated_Hotel`、`Budget_Hotel_Chain`、`Luxury_Hotel`、`Resort` |
|
|
26
|
+
| 停车场、parking | `Parking`;细分可用 `Indoor_Parking`、`Outdoor_Parking`、`Roadside_Parking` |
|
|
27
|
+
| 加油站、gas station | `Gas_Station` |
|
|
28
|
+
| 充电站、EV charging | `Ev_Charging_Station` |
|
|
29
|
+
| 地铁站、MRT、subway | `Subway_Light_Rail_Station` |
|
|
30
|
+
| 火车站 | `Train_Station` |
|
|
31
|
+
| 公交站 | `Bus_Stop` |
|
|
32
|
+
| 机场 | `Airport` |
|
|
33
|
+
| 医院、hospital | `General_Hospital`;细分可用 `Specialized_Hospital`、`Emergency_Center` |
|
|
34
|
+
| 诊所、clinic | `Clinics`;细分可用 `Private_Clinic`、`Community_Clinic`、`Dental_Clinic` |
|
|
35
|
+
| 药房、pharmacy | `Pharmacy` |
|
|
36
|
+
| 银行、bank | `Bank` |
|
|
37
|
+
| ATM | `Atm` |
|
|
38
|
+
| 商场、购物中心、mall | `Shopping_Mall`;泛化可用 `Shopping_Center` |
|
|
39
|
+
| 超市、supermarket | `Supermarket` |
|
|
40
|
+
| 便利店 | `Convenience_Store` |
|
|
41
|
+
| 公园 | `Urban_Park`;细分可用 `National_Park`、`Nature_Reserve` |
|
|
42
|
+
| 博物馆 | `Museum` |
|
|
43
|
+
| 图书馆 | `Library` |
|
|
44
|
+
| 健身房 | `Gym` |
|
|
45
|
+
|
|
46
|
+
## 一级类目
|
|
47
|
+
|
|
48
|
+
- `Transport_Mobility`:交通设施。
|
|
49
|
+
- `Entertainment_Leisure`:休闲娱乐。
|
|
50
|
+
- `Accommodation`:住宿服务。
|
|
51
|
+
- `Corporations_Industry`:公司企业。
|
|
52
|
+
- `Health_Medical`:医疗保健。
|
|
53
|
+
- `Residential`:房产住宅。
|
|
54
|
+
- `Tourism_Culture`:旅游与文化。
|
|
55
|
+
- `Government_Organizations`:机构团体。
|
|
56
|
+
- `Automotive_Services`:汽车服务。
|
|
57
|
+
- `Services_Daily_Life`:生活服务。
|
|
58
|
+
- `Geography`:自然地理。
|
|
59
|
+
- `Shopping_Retail`:购物零售。
|
|
60
|
+
- `Sports_Fitness`:运动健身。
|
|
61
|
+
- `Food_Drink`:餐饮美食。
|
|
62
|
+
|
|
63
|
+
## 交通设施
|
|
64
|
+
|
|
65
|
+
- 停车服务:`Parking`、`Park_And_Ride`、`Indoor_Parking`、`Roadside_Parking`、`Outdoor_Parking`
|
|
66
|
+
- 公路客运:`Bus_Coach`、`Bus_Stop`、`Tourist_Bus_Station`、`Coach_Station`
|
|
67
|
+
- 水路出行:`Water_Transport`、`Port_Wharf`、`Marina`、`Ferry_Terminal`
|
|
68
|
+
- 空港出行:`Air_Travel`、`Airport`、`Airport_Bus_Stop`、`Helipad`
|
|
69
|
+
- 能源补给:`Energy_Facilities`、`Gas_Refill_Station`、`Gas_Station`、`Battery_Swap_Station`、`Ev_Charging_Station`
|
|
70
|
+
- 铁路出行:`Rail_Transport`、`Entrance_Exit`、`Ticket_Office`、`Subway_Light_Rail_Station`、`Tram_Stop`、`Train_Station`
|
|
71
|
+
|
|
72
|
+
## 休闲娱乐与住宿
|
|
73
|
+
|
|
74
|
+
- 主题乐园:`Theme_Parks`、`Zoo`、`Botanical_Garden`、`Water_Park`、`Aquarium`、`Amusement_Park`
|
|
75
|
+
- 休闲场所:`Recreation`、`Ktv`、`Escape_Room_Larp`、`Chess_Card_Room`、`Arcade`、`Internet_Cafe_Esports`
|
|
76
|
+
- 影剧院:`Cinema_Theater`、`Theater`、`Opera_House`、`Cinema`、`Concert_Hall`
|
|
77
|
+
- 放松疗养:`Wellness`、`Spa`、`Bath_Center_Sauna`、`Beauty_Salon`、`Foot_Massage`
|
|
78
|
+
- 住宿服务:`Accommodation`、`Rv_Park`、`Campground`、`Inn`、`Homestay_Short_Term_Rental`、`Motel`、`Hostel`、`Hotels`、`Resort`、`Star_Rated_Hotel`、`Budget_Hotel_Chain`、`Luxury_Hotel`
|
|
79
|
+
|
|
80
|
+
## 医疗、教育与公共机构
|
|
81
|
+
|
|
82
|
+
- 医疗保健:`Health_Medical`、`Medical_Examination_Center`、`Veterinary_Clinic`、`Blood_Donation_Station`、`Pharmacy`、`Hospitals`、`Specialized_Hospital`、`Emergency_Center`、`General_Hospital`、`Clinics`、`Psychological_Counseling`、`Dental_Clinic`、`Community_Clinic`、`Private_Clinic`
|
|
83
|
+
- 教育机构:`Education`、`Middle_School`、`Training_Institution`、`College_University`、`Primary_School`、`Kindergarten`、`Driving_School`
|
|
84
|
+
- 政府机关:`Government`、`Embassy_Consulate`、`City_Hall_Government_Office`、`Courthouse`、`Fire_Station`、`Police_Station`
|
|
85
|
+
- 社会团体:`Social_Orgs`、`Association_Society`、`Welfare_House_Nursing_Home`、`Ngo`
|
|
86
|
+
|
|
87
|
+
## 旅游文化、自然地理与运动
|
|
88
|
+
|
|
89
|
+
- 公园广场:`Parks_Plazas`、`National_Park`、`Urban_Park`、`Nature_Reserve`、`Street_Plaza`
|
|
90
|
+
- 博览场馆:`Museums_Galleries`、`Museum`、`Library`、`Planetarium`、`Archives`、`Science_Museum`、`Art_Gallery`
|
|
91
|
+
- 名胜古迹:`Landmarks`、`World_Heritage`、`Historic_Site`、`Historic_Building`、`Monument_Statue`、`Observation_Deck`
|
|
92
|
+
- 宗教场所:`Religious_Places`、`Temple`、`Church`、`Mosque`、`Shrine`、`Taoist_Temple`
|
|
93
|
+
- 自然地理:`Geography`、`Island`、`River`、`Beach_Coastline`、`Lake`、`Peak`、`Forest`、`Desert`
|
|
94
|
+
- 运动健身:`Sports_Fitness`、`Bowling_Alley`、`Climbing_Gym`、`Ski_Resort`、`Tennis_Court`、`Badminton_Court`、`Golf_Course`、`Swimming_Pool`、`Basketball_Court`、`Stadium`、`Soccer_Field`、`Gym`、`Yoga_Pilates_Studio`、`Dance_Studio`
|
|
95
|
+
|
|
96
|
+
## 购物、生活与公司服务
|
|
97
|
+
|
|
98
|
+
- 购物中心:`Shopping_Centers`、`Duty_Free_Shop`、`Pedestrian_Street`、`Outlets`、`Department_Store`、`Shopping_Center`、`Shopping_Mall`
|
|
99
|
+
- 超市便利:`Groceries`、`Convenience_Store`、`Supermarket`、`Organic_Food_Store`、`Community_Supermarket`、`Market`
|
|
100
|
+
- 服饰鞋包:`Fashion_Accessories`、`Clothing_Store`、`Jewelry_Store`、`Luggage_Leather_Goods`、`Sports_Brand_Store`、`Watch_Shop`、`Shoe_Hat_Store`
|
|
101
|
+
- 家居建材:`Home_Garden`、`Hardware_Store`、`Furniture_Store`、`Home_Decor`、`Building_Materials_Market`、`Flower_Shop_Garden_Center`
|
|
102
|
+
- 生活服务:`Services_Daily_Life`、`Public_Toilet`、`Real_Estate_Agency`、`Laundry`、`Photo_Studio`、`Barber_Shop`、`Repair_Shop`
|
|
103
|
+
- 商务服务:`Business`、`Conference_Center`、`Coworking_Space`、`Consulting_Firm`、`Law_Firm`、`Travel_Agency`
|
|
104
|
+
- 金融服务:`Financial`、`Atm`、`Insurance_Company`、`Currency_Exchange`、`Bank`
|
|
105
|
+
- 公司办公:`Corporations_Industry`、`Offices`、`Corporate_Headquarters`、`Office_Building`、`Industrial_Park`
|
|
106
|
+
|
|
107
|
+
## 餐饮美食
|
|
108
|
+
|
|
109
|
+
- 中餐:`Chinese_Cuisine`、`Chinese_Fast_Food`、`Northern_Chinese_Cuisine`、`Sichuan_Cuisine`、`Dim_Sum`、`Halal_Lanzhou_Lamian`、`Hunan_Cuisine`、`Hot_Pot`、`Cantonese_Cuisine`、`General_Chinese_Cuisine`
|
|
110
|
+
- 亚洲餐厅:`Asian_Cuisine`、`Southeast_Asian_Cuisine`、`Indian_Cuisine`、`Japanese_Cuisine`、`Thai_Cuisine`、`Vietnamese_Cuisine`、`Korean_Cuisine`
|
|
111
|
+
- 咖啡茶饮:`Cafe_Tea_Dessert`、`Ice_Cream_Shop`、`Cafe`、`Milk_Tea_Juice_Shop`、`Dessert_Cake_Shop`、`Teahouse`、`Bakery`
|
|
112
|
+
- 快餐小吃:`Fast_Food_Snacks`、`Sandwich_Shop`、`Branded_Fast_Food`、`Salad_Light_Meal`、`Fried_Chicken_Shop`、`Deli`、`Street_Food`
|
|
113
|
+
- 西餐:`Western_Cuisine`、`Turkish_Kebab`、`Mexican_Latin_American_Cuisine`、`German_Cuisine`、`Italian_Cuisine`、`French_Cuisine`、`American_Cuisine`、`Spanish_Cuisine`
|
|
114
|
+
- 通用餐饮:`Dining_General`、`Restaurant`
|
|
115
|
+
- 酒吧夜生活:`Bars_Nightlife`、`Night_Club`、`Izakaya`、`Lounge_Bar`、`Craft_Beer_Bar`、`Bar_Pub`、`Cocktail_Bar`
|
|
116
|
+
|
|
117
|
+
## Agent 规则
|
|
118
|
+
|
|
119
|
+
- 用户明确输入类目英文枚举时,按原样使用;只修正明显大小写错误。
|
|
120
|
+
- 中文类目要映射到最具体的英文枚举;例如“大学”使用 `College_University`,不是 `school`。
|
|
121
|
+
- 用户只说“学校”且无法判断学段时,可以不用 `type`,或询问用户要大学/中学/小学/幼儿园。
|
|
122
|
+
- 用户只说“餐饮/吃饭”时,优先用 `Restaurant`;如果用户说咖啡、茶饮、甜品、快餐、火锅等,使用更具体类目。
|
|
123
|
+
- 对精准地点名、品牌名、校区名、地标名,不要默认增加类型过滤;类型过滤只用于“按类别找一批地点”的需求。
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# 信息窗口能力参考
|
|
2
|
+
|
|
3
|
+
当用户要求打开信息窗口、点击地图显示经纬度、Marker 绑定气泡、展示 POI 信息或自定义弹窗内容时,使用本参考。
|
|
4
|
+
|
|
5
|
+
## 能力范围
|
|
6
|
+
|
|
7
|
+
- 创建 `Maptec.Popup`。
|
|
8
|
+
- 设置位置、HTML、纯文本、偏移、宽度、关闭行为。
|
|
9
|
+
- 作为独立信息窗口添加到地图。
|
|
10
|
+
- 绑定到 `Maptec.Marker`。
|
|
11
|
+
- 监听打开、关闭事件。
|
|
12
|
+
|
|
13
|
+
## 点击地图增加信息窗口展示经纬度
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
let popup = null;
|
|
17
|
+
|
|
18
|
+
const onMapClick = (event) => {
|
|
19
|
+
const position = Maptec.LngLat.convert(event.lngLat).toArray();
|
|
20
|
+
const text = `经度:${position[0].toFixed(6)},纬度:${position[1].toFixed(6)}`;
|
|
21
|
+
|
|
22
|
+
if (!popup) {
|
|
23
|
+
popup = new Maptec.Popup({
|
|
24
|
+
position,
|
|
25
|
+
text,
|
|
26
|
+
closeButton: true,
|
|
27
|
+
closeOnClick: false
|
|
28
|
+
});
|
|
29
|
+
map.addOverlay(popup);
|
|
30
|
+
} else {
|
|
31
|
+
popup.position = position;
|
|
32
|
+
popup.text = text;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
map.on("click", onMapClick);
|
|
37
|
+
|
|
38
|
+
function cleanup() {
|
|
39
|
+
map.off("click", onMapClick);
|
|
40
|
+
if (popup) {
|
|
41
|
+
map.removeOverlay(popup);
|
|
42
|
+
popup.destroy?.();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 基础信息窗口
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
const popup = new Maptec.Popup({
|
|
51
|
+
position: [103.8198, 1.3521],
|
|
52
|
+
html: "<strong>Singapore</strong>",
|
|
53
|
+
offset: [0, -15],
|
|
54
|
+
maxWidth: "300px",
|
|
55
|
+
closeButton: true,
|
|
56
|
+
closeOnClick: true
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
map.addOverlay(popup);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Marker 绑定信息窗口
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
const popup = new Maptec.Popup({
|
|
66
|
+
offset: 25,
|
|
67
|
+
html: "<strong>National University of Singapore</strong>"
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const marker = new Maptec.Marker({
|
|
71
|
+
position: [103.7764, 1.2966],
|
|
72
|
+
color: "#2563eb",
|
|
73
|
+
popup
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
map.addOverlay(marker);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## 常用配置
|
|
80
|
+
|
|
81
|
+
- `position`: 信息窗口坐标
|
|
82
|
+
- `anchor`: 信息窗口锚点,未指定时 SDK 通常会动态调整。
|
|
83
|
+
- `html`: HTML 内容
|
|
84
|
+
- `text`: 纯文本内容
|
|
85
|
+
- `offset`: 像素偏移
|
|
86
|
+
- `maxWidth`: 最大宽度
|
|
87
|
+
- `className`: 自定义样式类
|
|
88
|
+
- `closeButton`: 是否显示关闭按钮
|
|
89
|
+
- `closeOnClick`: 点击地图时是否关闭
|
|
90
|
+
- `closeOnMove`: 地图移动时是否关闭
|
|
91
|
+
- `padding`: 用于让 Popup 避开地图边缘。
|
|
92
|
+
|
|
93
|
+
常用方法:
|
|
94
|
+
|
|
95
|
+
- `setDOMContent(element)`
|
|
96
|
+
- `getElement()`
|
|
97
|
+
- `isOpen()`
|
|
98
|
+
- `addClassName(className)`
|
|
99
|
+
- `removeClassName(className)`
|
|
100
|
+
- `destroy()`
|
|
101
|
+
- `isDestroyed()`
|
|
102
|
+
|
|
103
|
+
## DOM 内容
|
|
104
|
+
|
|
105
|
+
用户内容来自输入、服务结果或外部数据时,优先使用 `text` 或对 HTML 做清洗。
|
|
106
|
+
|
|
107
|
+
```js
|
|
108
|
+
const content = document.createElement("div");
|
|
109
|
+
content.textContent = "自定义 DOM 内容";
|
|
110
|
+
|
|
111
|
+
const popup = new Maptec.Popup({
|
|
112
|
+
position: [103.8198, 1.3521]
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
popup.setDOMContent(content);
|
|
116
|
+
map.addOverlay(popup);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## 事件
|
|
120
|
+
|
|
121
|
+
```js
|
|
122
|
+
const onOpen = () => console.log("信息窗口打开");
|
|
123
|
+
const onClose = () => console.log("信息窗口关闭");
|
|
124
|
+
|
|
125
|
+
popup.on("open", onOpen);
|
|
126
|
+
popup.on("close", onClose);
|
|
127
|
+
|
|
128
|
+
function cleanupPopupEvents() {
|
|
129
|
+
popup.off("open", onOpen);
|
|
130
|
+
popup.off("close", onClose);
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## 注意事项
|
|
135
|
+
|
|
136
|
+
- 独立信息窗口必须有 `position`。
|
|
137
|
+
- Marker 绑定信息窗口时,优先设置 `offset`,避免遮挡 Marker。
|
|
138
|
+
- 不要把用户输入直接拼接进 `html`。
|
|
139
|
+
- 清理时移除 Popup,并取消事件监听。
|
|
140
|
+
|
|
141
|
+
## Agent 规则
|
|
142
|
+
|
|
143
|
+
- 信息窗口必须使用 `new Maptec.Popup(...)`,并通过 `map.addOverlay(popup)` 或 Marker 绑定方式使用。
|
|
144
|
+
- 展示用户输入、POI 服务结果或外部数据时,优先使用 `text` 或安全 DOM,不要直接拼接到 `html`。
|
|
145
|
+
- 独立 Popup 必须提供 `position`;Marker 绑定 Popup 时应设置合理 `offset`。
|
|
146
|
+
- Popup 打开、关闭事件必须保存 handler,并在清理阶段解绑。
|