> **本文回答**：vjmap 样式规范基础 —— version / name / sources / layers / glyphs / sprite。

## 一、根结构

```js
{
  version: 8,                   // 必须 8
  name: "my-style",
  metadata: { ... },            // 任意
  center: [lng, lat],           // 默认中心
  zoom: 10,
  bearing: 0,
  pitch: 0,
  glyphs: "https://.../{fontstack}/{range}.pbf",
  sprite: "https://.../sprite",
  light: { anchor: "viewport", color: "#fff", intensity: 0.5, position: [1.15, 210, 30] },
  transition: { duration: 300, delay: 0 },
  sources: { /* ... */ },
  layers: [ /* ... */ ]
}
```

## 二、sources

### Raster（互联网瓦片 / CAD 栅格）

```js
"cad-raster": {
  type: "raster",
  tiles: ["https://vjmap.com/server/api/v1/raster/xxx/{z}/{x}/{y}.png"],
  tileSize: 256,                // vjmap CAD 栅格（svc.rasterStyle）与多数互联网瓦片都是 256；不写默认按 512
  minzoom: 0, maxzoom: 22
}
```

### Vector（矢量瓦片）

```js
"cad-vec": {
  type: "vector",
  tiles: ["https://vjmap.com/server/api/v1/mvt/xxx/{z}/{x}/{y}.pbf"]
  // 或 url: "https://xxx/tilejson.json"
}
// 使用时必须指定 source-layer
{ id: "roads", type: "line", source: "cad-vec", "source-layer": "roads" }
```

### GeoJSON

```js
"markers": {
  type: "geojson",
  data: { type: "FeatureCollection", features: [...] },
  // 或 data: "https://xxx.geojson"
  cluster: true,
  clusterRadius: 50,
  clusterMaxZoom: 14,
  clusterProperties: { sum: ["+", ["get", "weight"]] }
}
```

### Image / Video / Canvas

```js
"radar": {
  type: "image",
  url: "https://xxx/radar.png",
  coordinates: [[lng,lat], [lng,lat], [lng,lat], [lng,lat]]
}
```

### Raster-DEM（地形）

```js
"dem": { type: "raster-dem", tiles: ["https://.../{z}/{x}/{y}.png"] }   // encoding 省略 = "vjmaps"（即 Terrain-RGB 公式）；Terrarium 编码写 encoding: "terrarium"
```

⚠️ 发布版的 `encoding` 枚举只有 `"vjmaps"`（默认）/ `"terrarium"`——写其他值（如 `"terrain-rgb"`）校验不过（`is not a valid encoding type`）。

### WMS / WMTS / WFS / TMS

WMS：

```js
"wms": {
  type: "raster",
  tiles: ["https://xxx?bbox={bbox-epsg-3857}&srs=EPSG:3857&..."]
}
```

WMTS：

```js
"wmts": {
  type: "raster",
  tiles: ["https://xxx?REQUEST=GetTile&...&TILEMATRIX={z}&TILECOL={x}&TILEROW={y}"]
}
```

TMS：

```js
"tms": {
  type: "raster",
  tiles: ["https://xxx/{z}/{x}/{y}.png"],
  scheme: "tms"       // y 轴翻转
}
```

WFS（直接当 geojson）：

```js
"wfs": {
  type: "geojson",
  data: "https://xxx?service=WFS&request=GetFeature&outputFormat=application/json&..."
}
```

## 三、layers

通用字段：

```ts
{
  id: string,            // 唯一
  type: "background" | "fill" | "line" | "symbol"
      | "raster" | "circle" | "fill-extrusion"
      | "heatmap" | "hillshade" | "sky",
  source?: string,       // 除 background / sky 外必填
  "source-layer"?: string, // vector 必须
  minzoom?: number,      // 0~24 的任意数（可带小数）
  maxzoom?: number,
  filter?: Expression,
  layout?: {...},
  paint?: {...},
  metadata?: any
}
```

## 四、layer / paint / layout 动态修改

```js
// 添加
map.addLayer({ id: "x", type: "circle", source: "markers", paint: { "circle-radius": 5 } });

// 修改
map.setPaintProperty("x", "circle-color", "#f00");
map.setLayoutProperty("x", "visibility", "none");

// 过滤
map.setFilter("x", ["==", ["get", "type"], "building"]);

// 移除
map.removeLayer("x");
map.removeSource("markers");
```

## 五、glyphs / sprite

```js
glyphs: svc.glyphsUrl(),        // vjmap 内置的 URL 模板
sprite: svc.spriteUrl("mysprite") // {服务地址}sprite/{name}
```

- glyphs：文字字体（每 256 个字符一张 PBF）。
- sprite：图标精灵图（PNG + JSON）。

添加单张图片：

```js
map.loadImage("https://xxx.png", (err, img) => {
  if (!err) map.addImage("my-icon", img);
});

// layer 里用
{ id: "poi", type: "symbol", source: "markers", layout: { "icon-image": "my-icon" } }
```

## 六、light（3D 光照）

```js
map.setLight({
  anchor: "viewport",     // 或 "map"
  color: "#ffffff",
  intensity: 0.5,
  position: [1.15, 210, 30]
});
```

影响 `fill-extrusion` 图层的阴影。

## 七、transition（动画）

paint 属性变化的过渡时长在 style 根级 `transition` 字段配置：

```js
{
  version: 8,
  transition: { duration: 300, delay: 0 },
  ...
}
```

注意 `setPaintProperty(layer, name, value, options)` 的第 4 参是 `{ validate?: boolean }`（是否做样式校验），**不是** transition options。运行时改 paint 会按 transition 过渡（默认 300ms，颜色 / 透明度等可插值属性会渐变）；要立即生效，先把该属性的过渡设为 0：`map.setPaintProperty(id, name + "-transition", { duration: 0 })`（如 fill-color 对应 fill-color-transition），或在样式根级 `transition: { duration: 0 }`。

## 八、查询和导出

```js
const style = map.getStyle();     // 完整样式
const layers = style.layers;
const sources = style.sources;
map.setStyle(newStyle);                    // 整个替换
map.setStyle(newStyle, { diff: true });    // 差量更新（diff 是第 2 参 options 的字段，不是 style 的字段）
```

## 九、常见坑

1. **`source-layer`** 只在矢量瓦片里有，GeoJSON / Raster 不能填。
2. **Layer id 重复**：addLayer 会报错；先 `getLayer(id)` 判断。
3. **Sprite 缺失图标** → icon-image 没显示；必须图标名在 sprite JSON 里。
4. **`glyphs` 缺失**：带 `text-field` 的图层校验失败（`use of "text-field" requires a style "glyphs" property`），不是显示空方块；glyph PBF 404 则整个瓦片解析失败（该源该瓦片的所有图层都不出）。vjmap 默认用 `svc.glyphsUrl()`；自定义时记得 `glyphs: "https://.../{fontstack}/{range}.pbf"` 完整 URL。
