# SGS Map SDK API Reference
> 本项目同步版本: V2.5.0
> 适用对象: 第三方 H5、大屏、Kiosk、业务前端开发人员
> 发布源保留了 V2.3.0 文档标题和历史 API 注释;实际发行版本以 `package.json` 与 `dist` 产物自报的 2.5.0 为准。本文不表示本项目已经接入或验证 SDK iframe renderer。
本文档按公开 SDK 方法组织,说明初始化参数、事件、常用 API、返回值和错误处理。快速接入请先阅读 `sdk-quickstart.md`,底层通信协议请阅读 `sdk-protocol.md`。
## 1. 接入入口
### Script 标签
```html
```
如果 SDK 已随 `sgs-frontend-map` 发布到静态目录:
```html
```
### ESM
```ts
import SGSMapSDK from './dist/index.mjs';
const map = new SGSMapSDK({
container: document.getElementById('map-container')!,
sdkUrl: 'https://map.example.com/engine/index.html',
targetOrigin: 'https://map.example.com',
floorId: 1
});
```
## 2. 初始化配置
```ts
interface SGSMapSDKOptions {
container: string | HTMLElement;
sdkUrl?: string;
targetOrigin?: string;
floorId?: string | number;
mapId?: string | number;
timeout?: number;
readyTimeout?: number;
}
```
| 字段 | 必填 | 默认值 | 说明 |
|------|------|--------|------|
| `container` | 是 | 无 | 地图 iframe 挂载容器,可传 DOM id 或 HTMLElement |
| `sdkUrl` | 否 | `/engine/index.html` | 独立发布的 SDK 渲染引擎地址 |
| `targetOrigin` | 否 | 从 `sdkUrl` 推导 | `postMessage` 安全通信域,生产环境建议显式填写 |
| `floorId` | 否 | `1` | 初始楼层 ID,支持字符串或数字 |
| `mapId` | 否 | `1` | 地图 ID,当前由 SDK 实例保存 |
| `timeout` | 否 | `5000` | 普通命令超时时间,单位 ms |
| `readyTimeout` | 否 | `30000` | 等待 `ENGINE_READY` 的最大时间,单位 ms |
生产环境必须保证 `sdkUrl` 可访问,并且 `targetOrigin` 与 `sdkUrl` 的 Origin 一致。
## 3. 生命周期
### `whenReady(): Promise`
等待地图引擎 ready。所有需要基座响应的 API 建议在 ready 后调用。
```ts
await map.whenReady();
await map.changeFloor(2);
```
### `ready(): Promise`
`whenReady()` 的别名。
### `getIsReady(): boolean`
返回 SDK 是否已收到基座 `ENGINE_READY`。
### `destroy(): void`
销毁 SDK 实例,清理 iframe、事件监听和所有挂起 Promise。销毁后再调用异步命令会返回 `ERR_DESTROYED`。
```ts
window.addEventListener('beforeunload', () => {
map.destroy();
});
```
## 4. 状态查询
### `getCurrentFloor(): string | number`
返回 SDK 当前记录的楼层 ID。
### `getMapId(): string | number`
返回初始化时设置的 `mapId`。
### `getVersion(): string`
返回 SDK 版本号;本项目同步的 2.5.0 Bridge 返回 `"2.5.0"`。
### `getState(): Promise`
向渲染基座查询内部状态。主要用于调试或 Demo 面板。
```ts
const state = await map.getState();
console.log(state);
```
## 5. 地图控制
### `changeFloor(floorId, timeout?): Promise<{ success: boolean; floorId: string | number }>`
切换楼层。成功后 SDK 内部当前楼层会同步更新。
```ts
await map.changeFloor(2);
```
### `focusTo(node): void`
镜头聚焦到 POI、GLB 节点或坐标。
```ts
map.focusTo({ type: 'poiId', value: 10001 });
map.focusTo({ type: 'nodeName', value: 'Hall_Dinosaur' });
map.focusTo({ type: 'coord', floorId: 1, x: 12.5, z: -8.2 });
map.focusTo('Hall_Dinosaur');
```
`SgsMapNode` 类型:
```ts
type SgsMapNode =
| { type: 'coord'; floorId: string | number; x: number; z: number; y?: number }
| { type: 'poiId'; value: string | number }
| { type: 'nodeName'; value: string };
```
坐标统一使用 GLB/Three.js 米制坐标,水平面为 `x/z`,高度为 `y`。
### `resetView(): void`
重置相机视角。
### `setViewMode(mode): void`
切换 2D/3D 模式。
```ts
map.setViewMode('2d');
map.setViewMode('3d');
```
### `highlightPolygon(nodeName): void`
高亮指定 3D 场景节点对应的空间轮廓。
```ts
map.highlightPolygon('Hall_Area_01');
```
## 6. 图层控制
### `toggleLayer(types, visible, timeout?): Promise<{ success: boolean; visibleTypes: string[] }>`
批量控制指定类型图层的显示隐藏。
```ts
await map.toggleLayer(['TOILET', 'ELEVATOR'], true);
await map.toggleLayer(['STAIRS'], false);
```
### `setVisibleLayers(types, timeout?): Promise<{ success: boolean; visibleTypes: string[] }>`
设置当前可见的图层类型列表。
```ts
await map.setVisibleLayers(['TOILET', 'ELEVATOR', 'SERVICE_DESK']);
```
## 7. 图钉 Marker
### `addMarker(config): void`
添加业务图钉。
```ts
map.addMarker({
id: 'user-location',
name: '我的位置',
iconUrl: 'https://example.com/avatar.png',
position: { x: 10, y: 1.6, z: -5 }
});
```
`MarkerConfig`:
```ts
interface MarkerConfig {
id: string;
name?: string;
iconUrl?: string;
anchorNodeName?: string;
position?: [number, number, number] | { x: number; y: number; z: number };
}
```
### `removeMarker(markerId): void`
移除指定图钉。
```ts
map.removeMarker('user-location');
```
### `clearMarkers(): void`
清空所有业务图钉。
## 8. 路径规划
### `planRoute(from, to, options?, timeout?): Promise`
规划路线,兼容字符串节点名和结构化节点。
```ts
const route = await map.planRoute(
{ type: 'poiId', value: 8001 },
{ type: 'poiId', value: 9005 },
{ mode: 'walk' }
);
if (route.success) {
console.log(route.distance, route.duration, route.pathPoints);
}
```
也可传节点名:
```ts
await map.planRoute('一楼南卫生间', '生态大展区');
```
### `planRouteV2(from, to, options?, timeout?): Promise`
结构化参数版本。当前底层同样发送 `PLAN_ROUTE` 指令。
```ts
await map.planRouteV2(
{ type: 'coord', floorId: 1, x: 0, z: 0 },
{ type: 'coord', floorId: 1, x: 12, z: -6 },
{ mode: 'accessible' }
);
```
### `clearRoute(): void`
清除当前路线。
```ts
map.clearRoute();
```
`RouteResult` 主要字段:
```ts
interface RouteResult {
success: boolean;
distance: number;
duration: number;
pathPoints: Array<{ x: number; y: number; z: number }>;
computeTimeMs: number;
warnings: string[];
errorCode?: string;
message?: string;
}
```
## 9. 地图数据 API
### `getManifest(timeout?): Promise`
获取地图 Manifest,包含地图名称、楼层摘要、能力声明和版本信息。
```ts
const manifest = await map.getManifest();
console.log(manifest.mapName, manifest.sdkVersion, manifest.floors);
```
### `loadFloorBundle(floorId, timeout?): Promise`
一次性加载指定楼层的模型、POI、空间面、讲解点和路网摘要。
```ts
const bundle = await map.loadFloorBundle(1);
console.log(bundle.model.modelUrl);
console.log(bundle.pois.length, bundle.spaces.length, bundle.guideStops.length);
```
### `getFloorPois(floorId, timeout?): Promise`
获取指定楼层 POI 列表。
```ts
const pois = await map.getFloorPois(1);
pois.forEach(poi => console.log(poi.name, poi.type, poi.position));
```
### `getPois(floorCode, timeout?): Promise`
按楼层代码获取 POI 列表。该方法用于兼容既有基座能力,推荐新接入优先使用 `getFloorPois(floorId)`。
```ts
const pois = await map.getPois('L1');
```
### `getSpaces(floorId, timeout?): Promise`
获取指定楼层空间面列表。
```ts
const spaces = await map.getSpaces(1);
spaces.forEach(space => console.log(space.name, space.boundaryWkt));
```
### `getGuideStops(floorId, timeout?): Promise`
获取指定楼层已标定讲解点列表。
```ts
const stops = await map.getGuideStops(1);
stops.forEach(stop => console.log(stop.name, stop.audioUrl));
```
### `getGuideStopsByHall(hallId, timeout?): Promise`
获取指定展厅下的讲解点列表。
```ts
const stops = await map.getGuideStopsByHall('hall-001');
```
### `preloadFloor(floorId, timeout?): Promise<{ cached: boolean }>`
后台预加载指定楼层模型资源,不切换当前视图。
```ts
await map.preloadFloor(2);
```
### `clearModelCache(): void`
清空客户端模型缓存。
```ts
map.clearModelCache();
```
### `getNavigablePlaces(floorId, timeout?): Promise`
获取指定楼层的可导航目的地列表(v2.3.0+)。
```ts
const places = await map.getNavigablePlaces(1);
places.forEach(place => console.log(place.name, place.category));
```
## 10. 诊断接口 (v2.3.0+)
### `getDiagnostics(timeout?): Promise`
获取地图整体诊断信息,包含所有楼层摘要和汇总统计。用于检查数据完整性和就绪状态。
```ts
const diagnostics = await map.getDiagnostics();
console.log('地图状态:', diagnostics.status);
console.log('楼层总数:', diagnostics.summary.floorCount);
console.log('POI总数:', diagnostics.summary.poiCount);
console.log('可导航目的地总数:', diagnostics.summary.navigablePlaceCount);
// 检查警告信息
if (diagnostics.warnings.length > 0) {
console.warn('诊断警告:', diagnostics.warnings);
}
// 遍历楼层摘要
diagnostics.floors.forEach(floor => {
console.log(`${floor.floorName}: ${floor.status}, 可导航点=${floor.navigablePlaceCount}`);
});
```
**返回结构**:
```ts
interface SgsMapDiagnostics {
mapId: string | number;
mapName: string;
sdkVersion: string;
status: 'OK' | 'WARN' | 'ERROR';
floors: SgsFloorDiagnosticsSummary[];
summary: {
floorCount: number;
modelReadyFloorCount: number;
poiCount: number;
spaceCount: number;
guideStopCount: number;
navigablePlaceCount: number;
routeNodeCount: number;
routeEdgeCount: number;
};
warnings: string[];
}
```
### `getFloorDiagnostics(floorId, timeout?): Promise`
获取单个楼层的详细诊断信息。
```ts
const floorDiag = await map.getFloorDiagnostics(1);
console.log('楼层状态:', floorDiag.status);
console.log('模型就绪:', floorDiag.modelReady);
console.log('路径规划就绪:', floorDiag.routePlanningReady);
console.log('POI数量:', floorDiag.poiCount);
console.log('可导航目的地:', floorDiag.navigablePlaceCount);
```
**返回结构**:
```ts
interface SgsFloorDiagnostics {
floorId: string | number;
floorCode: string;
floorName: string;
status: 'OK' | 'WARN' | 'ERROR';
modelReady: boolean;
poiCount: number;
spaceCount: number;
guideStopCount: number;
navigablePlaceCount: number;
routeNodeCount: number;
routeEdgeCount: number;
routePlanningReady: boolean;
warnings: string[];
}
```
**使用场景**:
- 应用启动时检查地图数据是否完整
- 排查路径规划失败原因(检查 routePlanningReady)
- 监控数据发布后的就绪状态
- 生成数据健康报告
## 11. 性能监控
### `getPerformanceStats(timeout?): Promise`
获取 SDK 与渲染基座的性能统计。v2.3.0 保持合并 SDK 自身耗时与基座返回的模型加载耗时。
```ts
const stats = await map.getPerformanceStats();
console.table({
sdkReady: stats.engineReadyMs,
iframeDom: stats.iframeDomReadyMs,
manifest: stats.manifestLoadMs,
bundle: stats.bundleLoadMs ?? 'N/A',
model: stats.modelDownloadAndParseMs,
firstRender: stats.firstRenderMs
});
```
主要字段:
| 字段 | 说明 |
|------|------|
| `sdkCreatedAt` | SDK 实例创建时间戳 |
| `iframeDomReadyMs` | iframe DOM 加载完成耗时 |
| `engineReadyMs` | 地图引擎 ready 耗时 |
| `manifestLoadMs` | Manifest 加载耗时 |
| `bundleLoadMs` | Bundle 加载耗时,未触发时可能为空 |
| `modelDownloadMs` | 模型下载耗时 |
| `modelDownloadAndParseMs` | 模型下载与解析总耗时 |
| `modelParseMs` | 模型解析耗时 |
| `firstRenderMs` | 首帧渲染耗时 |
| `routePlanMs` | 路径规划耗时 |
| `dracoUsed` | 是否使用 Draco 压缩模型 |
| `fallbackUsed` | 是否使用 fallback 原始模型 |
| `currentFloorId` | 当前楼层 ID |
## 11. 事件
SDK 继承事件能力,可通过 `on(eventName, handler)` 监听事件。
```ts
map.on('ready', (info) => {
console.log('ready', info.engineVersion, info.protocolVersion);
});
map.on('poiClick', (poi) => {
console.log('poi clicked', poi.id, poi.name);
});
```
| 事件名 | Payload | 说明 |
|--------|---------|------|
| `ready` | `{ engineVersion, protocolVersion }` | 基座完全挂载,可安全调用 API |
| `poiClick` | `{ id, name, type, floorId?, description? }` | 用户点击 POI |
| `floorChanged` | `{ floorId }` | 楼层切换完成 |
| `error` | `{ code, message }` | 基座或 SDK 异常 |
| `loadError` | `{ type, detail }` | 资源加载异常 |
| `routeTransfer` | `{ currentFloorId, targetFloorId, transferType, ... }` | 跨楼层换乘提示 |
| `modelLoading` | `{ floorId, modelUrl }` | 模型开始加载 |
| `modelReady` | `{ floorId, parseTimeMs }` | 模型解析完成 |
| `modelError` | `{ floorId, error, fallbackUsed }` | 模型加载失败 |
| `floorBundleReady` | `{ floorId, dataVersion }` | 楼层 Bundle 数据加载完成 |
| `routeReady` | `{ routeId, distance, duration }` | 路径规划完成 |
## 12. 常用类型摘要
### `SgsSdkManifest`
```ts
interface SgsSdkManifest {
mapId: string | number;
mapName: string;
sdkVersion: string;
protocolVersion: number;
dataVersion: string;
updatedAt: string;
coordinateSystem: string;
floors: SgsSdkFloorSummary[];
capabilities: {
dracoCompression: boolean;
routePlanning: boolean;
spatialQuery: boolean;
guideStops: boolean;
// v2.3.0 新增标准能力字段
mapLoading?: boolean;
floorSwitching?: boolean;
poiQuery?: boolean;
spaceQuery?: boolean;
navigablePlaces?: boolean;
crossFloorRoute?: boolean;
accessibleRoute?: boolean;
highlight?: boolean;
diagnostics?: boolean;
};
}
```
### `SgsPoi`
```ts
interface SgsPoi {
id: string | number;
name: string;
type: string;
typeName: string;
floorCode: string;
position: { x: number; y: number; z: number };
status: 'ACTIVE' | 'INACTIVE';
anchorNodeName?: string | null;
description?: string;
iconUrl?: string;
}
```
### `SgsSpaceArea`
```ts
interface SgsSpaceArea {
id: string | number;
name: string;
type: string;
floorId: string | number;
boundaryWkt: string;
center: { x: number; y: number; z: number };
sourceNodeName?: string;
status: 'ACTIVE' | 'INACTIVE';
colorHex?: string;
}
```
### `SgsGuideStop`
```ts
interface SgsGuideStop {
id: string | number;
name: string;
type: string;
floorId: string | number;
position: { x: number; y: number; z: number };
targetType: string;
targetId?: string | number;
audioUrl?: string;
coverImageUrl?: string;
description?: string;
status: 'ACTIVE' | 'INACTIVE';
hallId?: string | number;
hallName?: string;
}
```
完整类型以 `dist/index.d.ts` 为准。
## 13. 错误处理
所有 Promise API 失败时会 reject 一个 `{ code, message }` 结构。
```ts
try {
await map.changeFloor(999);
} catch (err) {
console.warn(err.code, err.message);
}
```
| 错误码 | 说明 |
|--------|------|
| `ERR_TIMEOUT` | 命令响应超时 |
| `ERR_READY_TIMEOUT` | ready 超时,基座未发出 `ENGINE_READY` |
| `ERR_NOT_READY` | SDK ready 失败后继续调用命令 |
| `ERR_DESTROYED` | SDK 实例已销毁 |
| `ERR_IFRAME_LOAD` | iframe 加载失败 |
| `ERR_UNAUTHORIZED` | Origin 校验失败 |
| `ERR_UNSUPPORTED` | 当前基座不支持该命令 |
| `ERR_NO_PATH` | 路径规划无可达路线 |
| `ERR_FLOOR_NOT_FOUND` | 楼层不存在或未发布 |
| `ERR_NETWORK` | 网络或接口异常 |
## 14. 废弃方法
以下方法保留签名用于兼容旧接入方,新项目不要使用:
| 方法 | 状态 | 替代方案 |
|------|------|----------|
| `getReleaseManifest()` | 已废弃,返回 `ERR_UNSUPPORTED` | `getManifest()` |
| `getModelResources()` | 已废弃,返回 `ERR_UNSUPPORTED` | `loadFloorBundle()` |
| `getLayerTree()` | 已废弃,返回 `ERR_UNSUPPORTED` | 暂无 |
| `loadMockReleaseRoute()` | 已废弃,返回 `ERR_UNSUPPORTED` | `planRoute()` |
## 15. 第三方接入检查清单
- 页面中存在 SDK 挂载容器,且容器有稳定宽高。
- `sdkUrl` 可在浏览器直接访问,并能加载独立发布的 `/engine/index.html`。
- `targetOrigin` 与 `sdkUrl` 的 Origin 一致。
- 所有地图控制 API 在 `await map.whenReady()` 后调用。
- 坐标统一使用 GLB/Three.js 米制坐标,水平面为 `x/z`。
- 页面卸载时调用 `map.destroy()`。
- 生产发布时 SDK、Engine 与后端 Manifest 的 `sdkVersion` 必须保持兼容;本次 Bridge 为 `2.5.0`,上线前需验证 `/engine/index.html` 真实加载 SDK Engine 并完成 `HELLO` -> `ENGINE_READY`。