fromjson-fit
本文回答:
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 坐标)。
十二、常见坑
- fromJSON 后直接测试失败:没 fit;人眼不可见。
- 两张不同 DWG 的 doc 合并:坐标系不一致 → 显示错乱;不要跨图混用。
- bounds 全 0:可能实体的
boundingBox()未实现;调用ent.boundingBox()看返回值。 - 自定义实体未定义 boundingBox:
zoomExtents会漏掉它;自定义实体务必实现boundingBox()返回[minX, minY, maxX, maxY]。
相关
- 序列化 → drawing/serialize
- 批量加载 → batch/entity-bulk-add
- 打开图 → open-map/open-dwg