> **本文回答**：`mapcadLayer.fromJSON(doc)` 后图加载成功但看不到 —— 视图没有自动定位到实体范围。

## 一、症状

- `fromJSON` 没报错
- `mapcadLayer.getEntities().length > 0`（数据在里面）
- 画面上什么都看不到
- 拖拽 / 缩放地图也找不到

## 二、根因

`fromJSON` 把实体加载到 `mapcadLayer`，但**视图没有自动定位**到实体位置。如果地图当前视野在 `(0, 0)`，而实体坐标是 `(1000000, 500000)` → 实体在屏外。

## 三、修法：zoomExtents

```js
mapcadLayer.fromJSON(doc);
mapcadLayer.zoomExtents();      // 缩放到所有实体的范围（可加 padding 像素：zoomExtents(50)）
```

## 四、缩到自定义范围

实体包围盒用 `ent.boundingBox()`（CAD 坐标 `[minX, minY, maxX, maxY]`），再交给 vjmap 定位：

```js
// 自己算所有实体的总包围盒（CAD 坐标）
const box = [Infinity, Infinity, -Infinity, -Infinity];
for (const ent of mapcadLayer.getEntities()) {
  const b = ent.boundingBox();          // [minX, minY, maxX, maxY]
  if (!b) continue;
  box[0] = Math.min(box[0], b[0]); box[1] = Math.min(box[1], b[1]);
  box[2] = Math.max(box[2], b[2]); box[3] = Math.max(box[3], b[3]);
}
if (box[0] <= box[2]) {
  // GeoBounds 构造是 (min: GeoPoint, max: GeoPoint)——四数数组要用 fromArray
  map.fitMapBounds(vjmap.GeoBounds.fromArray(box), { padding: 50 });
}
```

注意：CAD 坐标用 `map.fitMapBounds(GeoBounds)`；`map.fitBounds` 吃的是经纬度 `LngLatBounds`，别混用。

## 五、定位到单个实体

```js
const ent = mapcadLayer.store.get(id);          // store.get(id)，不是 getById
if (ent) {
  const b = ent.boundingBox();                  // [minX, minY, maxX, maxY]
  map.fitMapBounds(vjmap.GeoBounds.fromArray(b), { padding: 100 });
}
```

## 六、加载时的完整流程

```js
async function loadDrawing(url) {
  const doc = await fetch(url).then(r => r.json());

  mapcadLayer.fromJSON(doc);

  // 必须的：定位视图
  mapcadLayer.zoomExtents();

  // 可选：选中第一个
  const first = mapcadLayer.getEntities()[0];
  if (first) mapcadLayer.store.setSelection([first.id]);
}
```

## 七、为什么不自动 fit

设计考虑：

- fromJSON 可能只是"继续上次的编辑"，保持当前视野
- 或追加一批新实体但不要跳视野

所以默认**不**改视图，需要用户显式调。

## 八、fit 的 padding

```js
map.fitMapBounds(bounds, {
  padding: { top: 50, bottom: 50, left: 50, right: 300 }
  // 右侧留给侧边面板
});
```

## 九、bounds 为空

```js
const ents = mapcadLayer.getEntities();
if (ents.length === 0) {
  console.warn('无实体，不 fit');
  return;
}
mapcadLayer.zoomExtents();
```

空范围下调用 fit 类 API 没有意义（且可能抛错）。

## 十、刚打开地图就 fromJSON

```js
const map = new vjmap.Map({ container: 'map', style: svc.rasterStyle(), ... });
map.attach(svc, prj);                         // 必须：坐标映射靠 map.getMapProjection()
await map.onLoad();
const mapcadLayer = new vjmapext.MapCadLayer();
map.addControl(mapcadLayer);                  // addControl 即 onAdd；onLoad 前挂或紧接 onLoad 后挂均可

mapcadLayer.fromJSON(doc);
mapcadLayer.zoomExtents();
```

顺序：new Map → **attach** → onLoad → addControl → fromJSON → zoomExtents（官方示例均是先 `await map.onLoad()` 再 `addControl`；先 addControl 再 onLoad 也行）。

> ⚠️ 坑位：onAdd 只在 `map.loaded()` 为真或 'load' 事件触发时连接渲染桶。若 `await onLoad()` 之后又 await 了别的异步、地图正在加载新瓦片时才 `addControl`，`loaded()` 可能为 false 而 'load' 不会再发 → 层**永久不接管渲染**。症状：addEntity 正常、store 有数据、画面什么都不画。补救：`map.fire('load')` 手动重发事件，或 removeControl 后重挂；预防：紧接 onLoad 挂，或在 onLoad 前挂。

## 十一、坐标系不匹配

如果 `doc.entities` 是 DWG 坐标，而 map 的 projection 是 WGS84 → 实体位置转换成经纬度可能飞到地球另一边。

排查：

```js
const sample = mapcadLayer.getEntities()[0];
console.log(sample.boundingBox());
// 看坐标数量级：
// CAD 坐标：几千~几百万
// 经纬度：-180~180 / -90~90
// 墨卡托：百万级
```

确保加载的 doc 坐标系和 mapcadLayer 期望的一致（一般都是 CAD 坐标）。

## 十二、常见坑

1. **fromJSON 后直接测试失败**：没 fit；人眼不可见。
2. **两张不同 DWG 的 doc 合并**：坐标系不一致 → 显示错乱；不要跨图混用。
3. **bounds 全 0**：可能实体的 `boundingBox()` 未实现；调用 `ent.boundingBox()` 看返回值。
4. **自定义实体未定义 boundingBox**：`zoomExtents` 会漏掉它；自定义实体务必实现 `boundingBox()` 返回 `[minX, minY, maxX, maxY]`。

## 相关

- 序列化 → [drawing/serialize](../drawing/serialize.md)
- 批量加载 → [batch/entity-bulk-add](../batch/entity-bulk-add.md)
- 打开图 → [open-map/open-dwg](../../../vjmap/references/open-map/open-dwg.md)
