> **本文回答**：Marker 拖拽 —— draggable / dragstart / drag / dragend。

## 一、启用拖拽

```js
const m = new vjmap.Marker({ draggable: true })
  .setLngLat([lng, lat]);
m.addTo(map);

// 运行时
m.setDraggable(true);
m.isDraggable();            // true
```

## 二、拖拽事件

```js
m.on("dragstart", () => {
  console.log("开始拖拽");
});

m.on("drag", () => {
  const ll = m.getLngLat();
  console.log("拖拽中", ll.lng, ll.lat);
});

m.on("dragend", () => {
  const ll = m.getLngLat();
  console.log("拖拽结束", ll);
});
```

## 三、clickTolerance（点击 vs 拖拽的容差）

```js
new vjmap.Marker({ draggable: true, clickTolerance: 3 })
```

鼠标在按下过程中移动超过 3 像素算拖拽，否则视为点击。

限制可发起拖拽的鼠标键（vjmap 引擎扩展，d.ts 未声明，TS 需 `// @ts-ignore`）：默认任意键都能拖；`disableDragButton` 列出禁止的键，取值 `left` / `middle` / `right` / `touch`，多个用逗号连接：

```js
const m2 = new vjmap.Marker({ draggable: true, disableDragButton: "middle,right" })  // 只允许左键和触摸拖动
  .setLngLat([lng, lat]);
m2.addTo(map);
```

## 四、实时显示坐标（在 Marker 上）

```js
const el = document.createElement("div");
el.style.cssText = "background:#fff;padding:4px;border:1px solid #aaa;cursor:move";
el.textContent = "拖我";

const m = new vjmap.Marker({ element: el, anchor: "bottom", draggable: true })
  .setLngLat([lng, lat]);
m.addTo(map);

m.on("drag", () => {
  const ll = m.getLngLat();
  el.textContent = `(${ll.lng.toFixed(5)}, ${ll.lat.toFixed(5)})`;
});
```

## 五、拖到指定位置后吸附

```js
m.on("dragend", () => {
  const ll = m.getLngLat();
  // 找最近的目标点
  const snapTo = findNearest(ll, candidates);
  if (distance(ll, snapTo) < 50) {
    m.setLngLat(snapTo);   // 吸附
  }
});
```

## 六、拖出边界回弹

```js
m.on("dragend", () => {
  const ll = m.getLngLat();
  const bounds = map.getMapExtent();            // CAD 全图范围（getGeoBounds() 默认只是全图×initViewScale/0.7）
  // ⚠️ GeoBounds.contains 只收 GeoPoint：先把经纬度转回 CAD 点再判定
  if (!bounds.contains(map.fromLngLat(ll))) {
    m.setLngLat(savedLastValidLngLat);
    alert("超出范围，已回弹");
  } else {
    savedLastValidLngLat = ll;
  }
});
```

## 七、拖动时同步 popup 位置

```js
const popup = new vjmap.Popup({ closeButton: false }).setText("拖我");
m.setPopup(popup);
m.togglePopup();            // 打开

m.on("drag", () => {
  // popup 会自动跟着 marker 移动，不用手动调整
});
```

## 八、禁止拖拽

```js
m.setDraggable(false);
```

## 九、坐标转 CAD

```js
m.on("dragend", () => {
  const ll = m.getLngLat();
  const cadPt = map.fromLngLat(ll);            // → { x, y }
  console.log("CAD 坐标", cadPt.x, cadPt.y);
});
```

## 十、常见坑

1. **拖拽过程中触发 click** → 用 `clickTolerance` 容差（默认 0 即继承 map）。
2. **拖拽后位置不对** → 可能 anchor 是 center 但视觉上以为是 bottom；拖的是几何中心。
3. **CSS 禁用 user-select**：`cursor: move; user-select: none;`，避免拖拽时选中文本。
4. **setDraggable(true) 后没拖** → 检查自定义 element 上有没有阻止 pointer 事件的 CSS。
5. **多个 Marker 同时拖**：vjmap Marker 是独立 DOM，可以独立拖；但 hitTest 顺序取决于 z-index。
