唯杰地图 logo唯杰地图
VJMAP
EN

multi-map

vjmap/references/overlay/multi-map.md 4.8 KB134 行
原文

本文回答:一个页面同时显示多张 vjmap 地图,视图同步;两张图卷帘比较;CAD 新旧图差异。

一、两张独立地图

<div id="map1" style="width: 50%; height: 100%; float:left"></div>
<div id="map2" style="width: 50%; height: 100%; float:left"></div>
async function initMap(containerId, mapid) {
  const svc = new vjmap.Service(URL, TOKEN);
  const res = await svc.openMap({ mapid, mapopenway: vjmap.MapOpenWay.GeomRender });
  const prj = new vjmap.GeoProjection(vjmap.GeoBounds.fromString(res.bounds));
  const map = new vjmap.Map({
    container: containerId,
    style: svc.rasterStyle(),
    center: prj.toLngLat(prj.getMapExtent().center()),
    zoom: 2,
    renderWorldCopies: false
  });
  map.attach(svc, prj);
  await map.onLoad();
  return map;
}

const map1 = await initMap("map1", "sys_zp");
const map2 = await initMap("map2", "sys_hello");

二、视图同步(zoom / center)

直接用内置 vjmap.syncMaps(任意张数,互相同步 center / zoom / bearing / pitch,内部同步时先摘掉监听防递归;返回解绑函数):

const unsync = vjmap.syncMaps(map1, map2);   // 也可 vjmap.syncMaps([map1, map2, map3])
// 不再同步时
unsync();

⚠️ 不要两边各挂一个无 guard 的 move → jumpTo:jumpTo 每次都同步 fire move,双向绑定会无限递归直至栈溢出(手写写法见 sync-view)。

三、卷帘 / swipe

内置 vjmap.Compare(两张地图叠放在同一容器内,自带滑块并自动 syncMaps;官方示例 map/mapcompare.js):

const compare = new vjmap.Compare(map1, map2, "#map", { mousemove: false, orientation: "vertical" });
compare.on("slideend", e => console.log("滑块停止"));
compare.setSlider(300);   // 程序设置滑块位置(像素)
compare.remove();         // 移除滑块并解除同步

或自建 DOM 遮罩 + 容器滑块方案:

<div id="container" style="position:relative;width:100%;height:100%">
  <div id="before"  style="position:absolute;inset:0"></div>
  <div id="after"   style="position:absolute;inset:0;clip-path:inset(0 50% 0 0)"></div>
  <div id="handle"  style="position:absolute;top:0;bottom:0;left:50%;width:4px;background:#000;cursor:ew-resize"></div>
</div>
const handle = document.getElementById("handle");
const after  = document.getElementById("after");
let dragging = false;
handle.onmousedown = () => dragging = true;
window.onmouseup   = () => dragging = false;
window.onmousemove = e => {
  if (!dragging) return;
  const rect = container.getBoundingClientRect();
  const ratio = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
  handle.style.left = ratio * 100 + "%";
  after.style.clipPath = `inset(0 ${(1 - ratio) * 100}% 0 0)`;
};

四、CAD 图版本比对(两张相同 mapid 的不同 version)

同上思路:svc.openMap({ mapid, version: "v1" }) 和 { version: "v2" }) 各打一张。

五、服务端图差分析

两张图的像素差可以直接在服务端算:

const diff = await svc.cmdMapDiff({
  mapid1, version1, layer1,
  mapid2, version2, layer2
});
// diff = { modify: [[pt,pt,..]], new: [...], del: [...], error? }

前端可视化差异:

function drawPolygons(map, points, color) {
  if (points.length === 0) return;
  points.forEach(p => p.push(p[0]));
  const polys = points.map(pts => ({
    points: map.toLngLat(pts),
    properties: { color }
  }));
  vjmap.createAntPathAnimateLineLayer(map, polys, {
    fillColor1: color,
    fillColor2: "#0ff",
    lineWidth: 4,
    lineOpacity: 0.8
  });
}
drawPolygons(map2, diff.modify, "#f00");    // 修改
drawPolygons(map2, diff.new,    "#0f0");    // 新增
drawPolygons(map1, diff.del,    "#00f");    // 删除

六、基于 mapCompare 命令(实体级比对)

mapCompare 比较两个图版本的实体数据,返回新增 / 删除 / 修改的实体;上面的 cmdMapDiff(mapDiff)才是像素比较(快,但只能定位差异区域、定位不到具体实体)。

const result = await svc.execCommand("mapCompare", {
  mapid1: "a", version1: "v1",
  mapid2: "b", version2: "v1"
}, "_null", "v1");

七、常见坑

  1. 同步后抖动 / 栈溢出:手写双向 move → jumpTo 会无限递归;用内置 vjmap.syncMaps,或加 guard(见 sync-view)。
  2. 两张图容器大小不一致:zoom 会看似对齐,实际投影像素不同;建议两张图等宽等高。
  3. 卷帘后 mouseover 穿透:pointer-events: none 在遮罩部分。
  4. mapCompare 在大图上超时 → 它逐实体比对数据,图大运算量大;只需定位差异区域时改用像素比较 cmdMapDiff。