> **本文回答**：vjmap 的常用数据源（`vector` / `raster` / `geojson` / `image` / `video`）用法与注意事项。

## 一、总览

```
type = "vector" | "raster" | "geojson" | "image" | "video"
```

> `SourceSpecification` 联合类型其实还有第 6 个成员 `raster-dem`（DEM 地形源，配合 `map.setTerrain()` 使用），仅做地形场景时才需要，日常五类即本节内容。

每个 source 有唯一 id，不能重复。vjmap.Map 提供标准的 `addSource` / `getSource` / `removeSource` 接口。

## 二、vector（矢量瓦片）

```js
map.addSource("cad-vec", {
  type: "vector",
  // 形如 {服务地址}map/tile/{mapid}/{version}/{layer}/{z}/{x}/{y}.mvt?tag={fileid}&token=xxx
  // layer 为样式图层名（默认 "main"）；tag 为 fileid（缓存标识，可省略）
  tiles: ["https://host/api/v1/map/tile/{mapid}/{version}/main/{z}/{x}/{y}.mvt?token=xxx"]
});
```

CAD 的几何渲染模式支持自带矢量瓦片：

```js
const { "vector-source": cadSrc } = svc.vectorStyle().sources;   // 源键为 `${prefix}-source`，prefix 缺省 "vector"
map.addSource("cad", cadSrc);
// 或直接 style: svc.vectorStyle()
```

配合 `map.enableVectorLayerHoverHighlight` 做客户端高亮。

## 三、raster（栅格瓦片）

```js
map.addSource("gaode", {
  type: "raster",
  tileSize: 256,                   // 默认 512
  tiles: [tileUrl]
});
map.addLayer({ id: "gaode-l", type: "raster", source: "gaode" });
```

`tileSize` 对互联网地图一般 256；vjmap CAD 栅格（`svc.rasterStyle()`）也是 256。

## 四、geojson

最常用的"业务数据图层"源。

```js
map.addSource("points", {
  type: "geojson",
  data: { type: "FeatureCollection", features: [] }
});

// 动态更新
map.getSource("points").setData(newFeatureCollection);
```

支持加载 URL（返回 GeoJSON）：

```js
map.addSource("markers", {
  type: "geojson",
  data: "./data/points.geojson"
});
```

### 聚合（cluster）

```js
map.addSource("pts", {
  type: "geojson",
  data,
  cluster: true,
  clusterRadius: 50,
  clusterMaxZoom: 14
});
```

详见 [marker/cluster](../marker/cluster.md)。

## 五、image（覆盖图像）

```js
map.addSource("flash", {
  type: "image",
  url: "./flash.gif",
  coordinates: [
    [lngLT, latLT], [lngRT, latRT],
    [lngRB, latRB], [lngLB, latLB]
  ]
});
map.addLayer({ id: "flash-l", type: "raster", source: "flash" });

// 更新位置
map.getSource("flash").setCoordinates([...]);
```

场景：把一张 PNG/JPG/GIF 定位到特定经纬度范围（批注、缩略图、动画）。

## 六、video（视频）

```js
map.addSource("vid", {
  type: "video",
  urls: ["https://host/a.mp4"],
  coordinates: [[lngLT,latLT],[lngRT,latRT],[lngRB,latRB],[lngLB,latLB]]
});
map.addLayer({ id: "vid-l", type: "raster", source: "vid" });
```

## 七、常用操作

```js
map.getSource("pts");            // 取 source（返回对象或 undefined）
!!map.getSource("pts");          // 判断是否存在（无 hasSource 方法）
map.removeSource("pts");         // 注意：先移除用到它的 layer 才能 removeSource
map.removeSourceEx("pts");       // vjmap 扩展：同时移除相关 layer
```

## 八、设计建议

- **一个 source 对应一批同类数据**（比如所有 Marker 点共用一个 geojson source），避免创建成百上千个 source。
- **setData 不要每帧调用**：大 FeatureCollection 会触发 worker 解析，几十 ms。
- **一个 source 可以有多个 layer**（比如同一个 points 加 circle、symbol、text 三个 layer）。
- **互联网底图**放最底，`moveLayer(id, firstLayerId)`。

## 九、常见坑

1. **removeSource 前没 removeLayer** → 报 `Source "x" cannot be removed while layer "y" is using it.`。**注意：它不是同步抛异常，而是 `fire(error)` 事件后提前返回**——`try/catch` 捕不到，要 `map.on("error", ...)` 才能截获；且 source 实际没被删除（之后 `getSource` 仍返回对象）。先 `removeLayer` 再 `removeSource`，或直接用 `removeSourceEx`。
2. **geojson `data` 是 URL 但 404** → 前端看不到任何图层；检查 Network。
3. **image source 的 `coordinates` 顺序错** → 图像变形倒置。顺序：左上 → 右上 → 右下 → 左下。
4. **vector source 的 `source-layer` 名错**：vector 图层定义需要 `source-layer`；若是 svc.vectorStyle() 已经配好，手动添加时记得配。
5. **`GeoJSONSource`/`ImageSource`/`CanvasSource`/`VideoSource` 类虽在 d.ts 声明、运行时顶层全是 `undefined`**——不能用 `new vjmap.GeoJSONSource({data})`。正确姿势就是本文档的 `map.addSource(id, spec对象)`；`getSource` 返回内部源实例（`type='geojson'`，带 `setData` 等方法）。
