唯杰地图 logo唯杰地图
VJMAP
EN

switching

vjmap/references/open-map/switching.md 4.1 KB122 行
原文

本文回答:三种切换当前图的方式(保留 map / 销毁重建 / 换 div),以及图层级开关控制。

一、三种切图方式

方式 什么时候用 优劣
map.switchMap({mapid}) 同一 map 对象,切换服务端的另一张图 状态保留、但必须确保两张图的打开方式一致
map.destory() + new vjmap.Map(...) 想换空白图 / 换打开方式 彻底重来,代价高
重建 div + 新 map DOM 结构需要刷新 最彻底,但闪一下

二、switchMap(推荐)

// 签名
map.switchMap(
  param,              // IOpenMapParam:与 svc.openMap 同结构
  isKeepOldLayers,    // 可选,是否保留之前添加的图层,默认 false
  isVectorStyle,      // 可选
  isSetCenter,        // 可选,是否默认设中心点
  isFitBounds,        // 可选,默认是否 fit
  source              // 可选,source id
): Promise;

使用:

await map.switchMap({
  mapid: "sys_world",
  mapopenway: vjmap.MapOpenWay.GeomRender,
  style: vjmap.openMapDarkStyle()  // 传给服务端 openMap,影响瓦片渲染风格
});

// 注意:前端用栅格还是矢量样式由第 3 个参数 isVectorStyle 决定,
// 与 param.style 无关。要切矢量:
await map.switchMap(
  { mapid: "sys_world", mapopenway: vjmap.MapOpenWay.GeomRender },
  false,   // isKeepOldLayers
  true     // isVectorStyle → svc.vectorStyle()
);

会依次触发 mapopenstart / mapopenfinish 事件:

map.on("mapopenstart", () => showLoading());
map.on("mapopenfinish", () => hideLoading());

三、销毁地图

map.destory();   // 注意:是 destory,不是 destroy(历史拼写)

然后就可以 new vjmap.Map(...) 挂到同一个 div 上。典型流程:

setInterval(async () => {
  map.destory();
  map = await newMap(SERVICE_URL, NEXT_MAPID);
}, 10_000);

newMap 是自己封装的完整 "打开 + 关联 + onLoad + 加业务图层" 流程。

四、换 div 重建

页面里每次 map 关联一个独立 div;旧 div 先清空,再挂新 div:

function createNewMapDivId() {
  const parent = document.getElementById("map");
  parent.innerHTML = "";
  const d = document.createElement("div");
  d.id = vjmap.RandomID(6);
  d.style.cssText = "position:absolute;width:100%;height:100%;";
  parent.appendChild(d);
  return d.id;
}

这种写法一般不推荐(会丢失引用),但做 A/B 测试或特殊调试时有用。

五、切图层(不切图)

不是换图,而是开关某些图层。栅格 vs 矢量走两条不同路径:

栅格瓦片:通过后端样式

await map.switchLayers(svc, onLayerNames);
// onLayerNames: ["图层A", "图层C"]  数组里的图层会显示,其他隐藏

矢量瓦片:通过前端 filter

思路是修改每个矢量图层的 filter 表达式,按 layer 索引过滤:

const onIdx = onLayerNames.map(name =>
  svc.getMapLayers().findIndex(l => l.name === name)
);
if (onIdx.length === 0) onIdx.push(-1);
const filter = ["match", ["get", "layer"], onIdx, true, false];

const style = map.getStyle();
const vectorStyle = svc.vectorStyle();
const vectorIds = new Set(vectorStyle.layers.map(l => l.id));
for (const layer of style.layers) {
  if (vectorIds.has(layer.id)) layer.filter = filter;
}
map.setStyle(style);

六、常见坑

  1. map.remove() vs map.destory():remove 释放 WebGL 上下文等底层资源;destory 是 vjmap 扩展(兼容旧代码,内部会调用 remove 并清理 svc/prj 引用)。切图前用 destory 更彻底。
  2. 切图后拿到旧 svc → map.switchMap 只换 map;如果要同时换服务,需要重新 new vjmap.Service 并 map.attach(newSvc, newPrj)。
  3. 切图时大量历史监听没清 → map.off 所有业务监听或统一通过一个 bus 管理。
  4. 用 switchMap 却传了不兼容的 mapopenway → 报错或空白。建议切图前先确认新图的打开方式。