唯杰地图 logo唯杰地图
VJMAP
EN

fromjson-fit

vjmapext/references/trouble/fromjson-fit.md 5.0 KB146 行
原文

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

一、症状

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

二、根因

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

三、修法:zoomExtents

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

四、缩到自定义范围

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

// 自己算所有实体的总包围盒(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,别混用。

五、定位到单个实体

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 });
}

六、加载时的完整流程

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

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

九、bounds 为空

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

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

十、刚打开地图就 fromJSON

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 → 实体位置转换成经纬度可能飞到地球另一边。

排查:

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]。

相关