唯杰地图 logo唯杰地图
VJMAP
EN

geojson-source

vjmap/references/primitive/geojson-source.md 5.8 KB222 行
原文

本文回答:GeoJSON source 全面用法 —— addSource / setData / 属性更新 / cluster / lineMetrics / filter。

一、创建 GeoJSON source

map.addSource("mySrc", {
  type: "geojson",
  data: featureCollection
});

// 或 URL
map.addSource("mySrc", {
  type: "geojson",
  data: "https://example.com/a.geojson"
});

// vjmap 扩展:
map.addGeoJSONSource("mySrc", featureCollection);

二、source 选项

选项 默认 说明
data — GeoJSON / URL
generateId false 为 feature 自动生成 id,feature-state 必需
lineMetrics false 计算线进度,line-gradient 必需
cluster false 启用点聚合
clusterRadius 50 聚合半径(像素)
clusterMaxZoom — 超过该 zoom 不聚合
clusterMinPoints 2 最少几点算一簇
clusterProperties — 聚合时的属性聚合函数
tolerance 0.375 简化容差
buffer 128 瓦片缓冲
maxzoom 18 切瓦片的最大 zoom
attribution — 版权文字
promoteId — 提升某个属性为 id

三、更新数据 setData

map.getSource("mySrc").setData(newFeatureCollection);

// 小修改 → 传新 FC,一次性替换

注意:GeoJSON source 没有 "patch",每次都要传完整数据。如果只改几十个 feature,最好在前端缓存副本。

四、按 promoteId 把属性当 id

map.addSource("mySrc", {
  type: "geojson",
  data,
  promoteId: "gid"     // feature.properties.gid → feature.id
});

// 之后就可 setFeatureState
map.setFeatureState(
  { source: "mySrc", id: 123 },
  { hover: true }
);

五、feature-state API

// 读
const state = map.getFeatureState({ source: "mySrc", id: 123 });

// 写
map.setFeatureState({ source: "mySrc", id: 123 }, { hover: true });

// 清除单 feature
map.removeFeatureState({ source: "mySrc", id: 123 }, "hover");

// 清除整 source
map.removeFeatureState({ source: "mySrc" });

六、query 所有 feature

// 整源查
const feats = map.querySourceFeatures("mySrc");

// 屏幕上可见的(必须指定图层)
const rendered = map.queryRenderedFeatures(e.point, { layers: ["layer1"] });

// 按 filter 查
const subset = map.querySourceFeatures("mySrc", {
  filter: ["==", ["get", "type"], "POI"]
});

七、cluster 聚合点

map.addSource("pts", {
  type: "geojson",
  data: pointFc,
  cluster: true,
  clusterRadius: 50,
  clusterMaxZoom: 14,
  clusterProperties: {
    sum: ["+", ["get", "val"]]
  }
});

map.addLayer({
  id: "clusters", type: "circle", source: "pts",
  filter: ["has", "point_count"],
  paint: {
    "circle-radius": ["step", ["get", "point_count"], 15, 10, 20, 50, 25],
    "circle-color": ["step", ["get", "point_count"], "#0f0", 10, "#ff0", 50, "#f00"]
  }
});

map.addLayer({
  id: "cluster-count", type: "symbol", source: "pts",
  filter: ["has", "point_count"],
  layout: {
    "text-field": ["get", "point_count_abbreviated"],
    "text-size": 12
  }
});

map.addLayer({
  id: "unclustered", type: "circle", source: "pts",
  filter: ["!", ["has", "point_count"]],
  paint: { "circle-radius": 5, "circle-color": "#11b4da" }
});

// 点击展开
map.on("click", "clusters", e => {
  const feat = e.features[0];
  const cid = feat.properties.cluster_id;
  map.getSource("pts").getClusterExpansionZoom(cid, (err, zoom) => {
    if (err) return;
    map.easeTo({ center: feat.geometry.coordinates, zoom });
  });
});

八、lineMetrics 用法

map.addSource("route", {
  type: "geojson",
  data: lineFc,
  lineMetrics: true        // 必须
});

map.addLineLayer("route-line", "route", {
  lineWidth: 6,
  lineGradient: [
    "interpolate", ["linear"], ["line-progress"],
    0, "#0f0",
    1, "#f00"
  ]
});

九、GeoJSON 格式小抄

// Point
{ type: "Point", coordinates: [x, y] }

// LineString
{ type: "LineString", coordinates: [[x,y],[x,y]] }

// Polygon(外环 + 多个孔)
{ type: "Polygon", coordinates: [
  [[x,y],[x,y],...,[x,y]],      // 外
  [[x,y],...,[x,y]]             // 孔(可选)
]}

// MultiPolygon
{ type: "MultiPolygon", coordinates: [
  [ [外], [孔] ],
  [ [外] ]
]}

// FeatureCollection
{ type: "FeatureCollection", features: [
  { type: "Feature", geometry: {...}, properties: {...}, id: 1 }
]}

十、geometry-type 过滤

在多几何混合 source 上,按几何类型分图层:

map.addFillLayer("poly", "mySrc", {
  fillColor: "#0af",
  filter: ["==", ["geometry-type"], "Polygon"]
});

map.addLineLayer("line", "mySrc", {
  lineColor: "#f00",
  filter: ["==", ["geometry-type"], "LineString"]
});

map.addCircleLayer("pt", "mySrc", {
  circleColor: "#f00",
  filter: ["==", ["geometry-type"], "Point"]
});

注意:老写法是 ["==", "$type", "LineString"],新写法 ["==", ["geometry-type"], "LineString"]。

十一、常见坑

  1. setData 整份数据大 → 卡顿 → cluster / 切瓦片 / 按视野分片加载。
  2. feature-state 不生效 → 没 id(generateId: true 或 promoteId)。
  3. URL data 跨域 → 后端加 CORS。
  4. 很多小的 source → 合并成一个带 filter 的 source,性能更好。
  5. updates 时图层闪烁 → 先 setData 再渲染帧;别在每帧 setData。
  6. querySourceFeatures 返回空:geojson 的瓦片索引只在有图层引用该 source 且视口覆盖到数据时才生成——只 addSource 不加图层、或数据在当前视口外,查询恒返回 []。且 setData 后旧瓦片会先命中(新瓦片异步重建),需要按数量/内容轮询而非查一次。