> **本文回答**：锚点 anchor 与偏移 offset 的数学关系 —— 缩放时保持位置不动的正确设法。

## 一、直觉

Marker 的 lngLat 是一个**点**，但图标是一个**矩形**。`anchor + offset` 决定"矩形的哪一点对齐在这个点上"。

```
default: anchor=center, offset=[0,0]
→ 矩形中心在 lngLat
```

## 二、九宫锚点图

```
     top-left       top       top-right
    ┌───────────┬────────────┬───────────┐
    │           │            │           │
    │ left      │ center     │ right     │
    │           │            │           │
    ├───────────┼────────────┼───────────┤
    │           │            │           │
    │bottom-left│ bottom     │bottom-right│
    └───────────┴────────────┴───────────┘
```

## 三、偏移 offset 含义

offset 是"对齐点再偏移的像素量"，`[x, y]`：x 正为右，y 正为下，负数反之。

## 四、经典问题：水滴尖尖指向目标点

默认图标高 41px，尖尖在底端。

- **方式 A**：`anchor: "bottom"` → 矩形底端对齐在 lngLat。
- **方式 B**：`anchor: "center", offset: [0, -20]` → 中心对齐后再上移 20 像素。

等效，任选其一。

## 五、典型实战

### 5.1 图片 Marker（32×40，尖尖在底）

```js
new vjmap.Marker({
  element: el,
  anchor: "bottom"
}).setLngLat([lng, lat]).addTo(map);
```

### 5.2 POI 标签（下面是小圆点）

```html
<div class="poi">
  <div class="label">名称</div>
  <div class="dot"></div>
</div>
```

希望"小圆点"精确对齐 lngLat：

```js
// 假设小圆点在整个 div 的最底端中间
new vjmap.Marker({ element: el, anchor: "bottom" }).setLngLat([lng, lat]).addTo(map);
```

### 5.3 气泡提示（尖尖在左下）

```js
new vjmap.Marker({ element: el, anchor: "bottom-left" })
  .setLngLat([lng, lat])
  .addTo(map);
```

## 六、anchor + offset 复合用

比如 50×30 的卡片，希望"卡片中心"对齐目标点下方 20px（让目标点上方显示卡片）：

```js
new vjmap.Marker({
  element: el,            // 50×30
  anchor: "center",
  offset: [0, -35]        // 目标点上方 35px（= 卡片高度 / 2 + 20）
}).setLngLat([lng, lat]).addTo(map);
```

## 七、缩放时位置不动的原理

Marker 永远定位在 lngLat 这个**地理点**上。缩放地图时：

- 地理坐标 lngLat 不变；
- 屏幕像素变化，但 Marker 的 anchor 点始终对齐 lngLat → **在几何意义上不动**。
- 视觉上 div 大小不变，但相对地图缩放。

### 7.1 "为什么我的 Marker 看起来在动？"

- 初始 anchor 错：`anchor: "center"` + 高 60 的 div，低 zoom 时图标中心在屏幕某位置，拉高 zoom 后由于地图放大，但 div 大小不变，视觉上"锚点飘了"。
- 修复：用 `anchor: "bottom"`，尖尖总是落在目标点。

## 八、自动缩放 scaleMaxZoom

让 div 随地图一起缩小：

```js
vjmap.createMarker({ scaleMaxZoom: 16, anchor: "center" })  // scaleMaxZoom 是扩展字段，须走 createMarker
  .setLngLat([lng, lat]).addTo(map);
```

当 zoom > 16 时正常显示；zoom < 16 时 div 按比例缩小，防止挤堆。

## 九、pitchAlignment / rotationAlignment

倾斜 / 旋转地图时：

```js
// Marker 始终贴地（随地图倾斜变扁）
new vjmap.Marker({ pitchAlignment: "map", rotationAlignment: "map" })
  .setLngLat(...).addTo(map);

// Marker 始终正对屏幕（默认）
new vjmap.Marker({ pitchAlignment: "viewport", rotationAlignment: "viewport" })
  .setLngLat(...).addTo(map);
```

## 十、常见坑

1. **认为 offset 是地理单位** → offset 是**像素**。
2. **anchor 忘写** → 默认 center；图片图标看起来"浮在空中"。
3. **CSS transform 混乱** → Marker 内部用 `translate()` 定位；不要在外层 div 再加 `transform` 覆盖，否则位置错乱。
4. **不同 DPR 下看起来偏** → 检查 devicePixelRatio；offset 是 CSS 像素，不受 DPR 影响。
5. **拖拽后位置不对** → dragend 事件里检查 `marker.getLngLat()`，可能拖的是 div 中心，而 anchor 是 bottom，转换要一致。
