> **本文回答**：一个页面同时显示多张 vjmap 地图，视图同步；两张图卷帘比较；CAD 新旧图差异。

## 一、两张独立地图

```html
<div id="map1" style="width: 50%; height: 100%; float:left"></div>
<div id="map2" style="width: 50%; height: 100%; float:left"></div>
```

```js
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，内部同步时先摘掉监听防递归；返回解绑函数）：

```js
const unsync = vjmap.syncMaps(map1, map2);   // 也可 vjmap.syncMaps([map1, map2, map3])
// 不再同步时
unsync();
```

⚠️ 不要两边各挂一个无 guard 的 `move → jumpTo`：`jumpTo` 每次都同步 fire `move`，双向绑定会无限递归直至栈溢出（手写写法见 [sync-view](sync-view.md)）。

## 三、卷帘 / swipe

内置 `vjmap.Compare`（两张地图叠放在同一容器内，自带滑块并自动 `syncMaps`；官方示例 `map/mapcompare.js`）：

```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 遮罩 + 容器滑块方案：

```html
<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>
```

```js
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" })` 各打一张。

## 五、服务端图差分析

两张图的像素差可以直接在服务端算：

```js
const diff = await svc.cmdMapDiff({
  mapid1, version1, layer1,
  mapid2, version2, layer2
});
// diff = { modify: [[pt,pt,..]], new: [...], del: [...], error? }
```

前端可视化差异：

```js
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`）才是**像素比较**（快，但只能定位差异区域、定位不到具体实体）。

```js
const result = await svc.execCommand("mapCompare", {
  mapid1: "a", version1: "v1",
  mapid2: "b", version2: "v1"
}, "_null", "v1");
```

## 七、常见坑

1. **同步后抖动 / 栈溢出**：手写双向 `move → jumpTo` 会无限递归；用内置 `vjmap.syncMaps`，或加 guard（见 [sync-view](sync-view.md)）。
2. **两张图容器大小不一致**：zoom 会看似对齐，实际投影像素不同；建议两张图等宽等高。
3. **卷帘后 mouseover 穿透**：`pointer-events: none` 在遮罩部分。
4. **`mapCompare` 在大图上超时** → 它逐实体比对数据，图大运算量大；只需定位差异区域时改用像素比较 `cmdMapDiff`。
