> **本文回答**：与"地图"相关、但不属于查询/导出/样式等专题的杂项 API：元数据、坐标变换、组合图、临时图。

## 一、元数据 / 常量

```js
// 当前图最近一次打开的参数
const p = svc.currentMapParam();
// p = { mapid, version, bounds, drawBounds, darkMode, ... }

// 任意图的元数据（远程）
const meta = await svc.metadata(mapid, version);
// meta.bounds / dbBounds / drawBounds / initBounds / viewBounds, meta.layers / meta.styles（SDK 已 JSON.parse 为数组）,
// meta.defaultlayer, meta.blockReferences, meta.layouts, meta.initCenterX/Y / initZoom, ...

// 实体类型 ID → 名称 映射
const { entTypeIdMap } = await svc.getConstData();
// { "1":"AcDbLine", "2":"AcDbPolyline", ... }
```

## 二、CAD 实际绘图范围

`res.bounds` 是 CAD 图的 extend；精确获取"有实体的区域"：

```js
// 方式 0：零成本 —— openMap 响应里就带 drawBounds
const res = await svc.openMap({ mapid, mapopenway: vjmap.MapOpenWay.GeomRender });
res.drawBounds;   // "[x1,y1,x2,y2]" 字符串，精度同方式 A 级别

// 方式 A：准确（请求后端计算，稍慢；仅几何库实现——Memory 方式打开的图恒返回 null，须判空回退方式 B）
const drawBounds = (await svc.cmdGetDrawBounds(mapid, res.version)) ?? svc.currentMapParam()?.drawBounds;

// 方式 B：快速（本地 currentMapParam 的 cache；未 attach 过 Map 时可能为 null，须判空）
const approx = svc.currentMapParam()?.drawBounds;   // openMap 成功后即填充
```

## 三、坐标变换（跨坐标系）

```js
// EPSG:4527 → EPSG:4326 WGS84 （数组形式批量）
const res = await svc.cmdTransform(
  "EPSG:4527",
  "EPSG:4326",
  vjmap.geoPoint([x, y])
);
const wgs = res[0];
```

支持传入单点或点数组。详见 [coord/gis-transforms](../coord/gis-transforms.md)。

## 四、执行命令 `execCommand`

大多数"服务端命令"通过 `execCommand` 调用：

```js
const result = await svc.execCommand(
  commandName,    // "exportPdf" / "exportDxf" / "objectDetection" / ...
  param,          // 命令参数对象
  mapid,          // 要操作的 mapid（不填用当前）
  version,        // 版本号
  useGet          // true 走 GET，false/省略走 POST
);
if (result.error) throw new Error(result.error);
```

常用命令：

| 命令 | 作用 | 典型 param |
|---|---|---|
| `exportPdf` | 导出 PDF | `{ pageWidth, pageHeight, geomDPI, ... }` |
| `exportDxf` | 导出 DXF/DWG | `{}` |
| `getDataBounds` | 获取实际绘图范围（即 `svc.cmdGetDrawBounds()` 内部调的命令） | `{}` |
| `objectDetection` | 实体识别（仅几何渲染图） | `{ mapid, version, pattern, bounds, ... }`——mapid 放参数里、URL 用 `"_null","v1"`（`extractTable`/`extractCenterLines` 同理，见 [query-cases](query-cases.md)） |
| `composeNewMap` | 合成新图（注意命令名带 `New`） | `{ mapid, fourParameter, layers, ... }` |

## 五、组合 / 重排 / 变换新图

不修改原图，生成一个"变换后的临时新图"：

```js
// 旋转 90 度生成新图
const composeRes = await svc.composeNewMap({
  mapid: "cbf527ed3ad1",
  version: "v1",
  fourParameter: [0, 0, 1, -Math.PI / 2]   // dx,dy,scale,rotate(弧度)
});
// composeRes.fileid = 新生成的 dwg fileid

// 用 updateMap 把它注册为临时图
const upd = await svc.updateMap({
  mapid: vjmap.getTempMapId(1),     // 1 分钟后过期
  fileid: composeRes.fileid,
  mapopenway: vjmap.MapOpenWay.Memory
});
```

## 六、临时图

```js
// 获取一个 N 分钟后自动删除的 mapid
const tempId = vjmap.getTempMapId(30, false);
// 以 "ns_temp_30_" 开头，云端管理台不可见
// 第二个参数 isVisible = true 时对管理台可见
```

用途：导出、合成中间图、AI 生成的临时 DWG。

## 七、切图层 / 切样式

```js
// 栅格：switchLayers
await map.switchLayers(svc, ["要显示的图层名1", "要显示的图层名2"]);

// 切换至矢量瓦片
await map.switchMap({ mapid, mapopenway: vjmap.MapOpenWay.GeomRender }, true, true);
```

详见 [open-map/switching](../open-map/switching.md)。

## 八、画布导出为 PNG（前端）

```js
// 初始化时：preserveDrawingBuffer: true
const dataUrl = map.getCanvas().toDataURL();
```

## 九、常见坑

1. **`svc.openMap()` 会写内部缓存**：`_waitOpenMap` 把响应 `data` 存入 `_cur_map_param`，成功后 `currentMapParam()`、`getMapLayers()` 直接可用，**无需** `setCurrentMapParam` 手动补。`getMapLayers()` 依赖响应里的 `layers` 字段，openMap 返回值已含。
2. **`metadata` 跨 mapid 但忘切 workspace** → 返回 404。
3. **`composeNewMap` 生成的 fileid 未用 updateMap 注册** → 直接 openMap 打不开，因为它还没绑定 mapid。
