唯杰地图 logo唯杰地图
VJMAP
EN

line

vjmap/references/primitive/line.md 7.3 KB198 行
原文

本文回答:vjmap.Polyline 线图元 —— 宽度 / 虚线 / 渐变 / 图案 / 动画。

一、最小示例

const polyline = new vjmap.Polyline({
  data: map.toLngLat(featureCollection),
  lineColor: "#f00",
  lineWidth: 3,
  isHoverPointer: true,
  isHoverFeatureState: true
});
polyline.addTo(map);

二、核心参数(驼峰式)

参数 默认 说明
data — GeoJSON LineString 或 FeatureCollection
lineColor #000 线颜色
lineWidth 1 线宽(像素)
lineOpacity 1 透明度
lineCap butt 端点样式:butt / round / square
lineJoin miter 连接样式:bevel / round / miter
lineMiterLimit 2 miter 阈值(d.ts 里的 lineMiterMimit 是拼写错误:该选项被静默忽略,polyline.setLineMiterMimit() 抛 TypeError;运行时改用 map.setLineMiterLimit(poly.getLayerId(), v))
lineRoundLimit 1.05 round 阈值
lineOffset 0 平行偏移(像素)
lineBlur 0 模糊
lineDasharray — 虚线数组 [实,虚,实,虚,...](单位 = 线宽倍数)
linePattern — 平铺图案(图像名)
lineGradient — 沿线渐变(需 source lineMetrics: true)
lineTranslate [0,0] 平移(像素)
lineTranslateAnchor map map/viewport
lineGapWidth 0 平行双线间距
lineSortKey — 同层排序
isHoverPointer false hover 改 cursor
isHoverFeatureState false hover 自动 setFeatureState

三、虚线

new vjmap.Polyline({
  data,
  lineColor: "#00f",
  lineWidth: 2,
  lineDasharray: [2, 4]   // 2 倍线宽实线,4 倍线宽虚线
});

复杂虚线:

lineDasharray: [1, 2, 5, 2]  // 实1 空2 实5 空2

四、渐变线(沿线颜色)

// 必须在 source 上加 lineMetrics
map.addSource("route", { type: "geojson", data: lineFeatures, lineMetrics: true });

const poly = new vjmap.Polyline({
  sourceId: "route",
  data: undefined,
  lineWidth: 6,
  lineGradient: [
    "interpolate", ["linear"], ["line-progress"],
    0, "#0f0",
    0.5, "#ff0",
    1, "#f00"
  ]
});

注:设了 lineGradient 时 lineColor 被忽略(两者可共存);lineGradient 与 linePattern 互斥,源必须 lineMetrics: true。

⚠️ 复用外部 sourceId 时,poly.remove() 会连源及该源上的所有图层一起删(内部 removeSourceEx);只删本层用 map.removeLayer(poly.getLayerId())。

五、线型图案(沿线平铺)

await map.loadImageEx("pattern", "/images/line-pattern.png");

new vjmap.Polyline({
  data,
  lineWidth: 20,
  linePattern: "pattern"
});

六、粗细随 zoom

lineWidth: [
  "interpolate", ["linear"], ["zoom"],
  10, 1,
  14, 3,
  18, 8
]

七、按属性变色

lineColor: [
  "match", ["get", "level"],
  "main", "#f00",
  "sub", "#0f0",
  "#888"
]

八、平行双线(公路)

new vjmap.Polyline({ data, lineColor: "#000", lineWidth: 6 }).addTo(map);   // 先加:底层黑色宽线
new vjmap.Polyline({ data, lineColor: "#fff", lineWidth: 2 }).addTo(map);   // 后加:叠在上面的白色细线

后加的图层在上,所以先加黑线再加白线。lineGapWidth 不是"中间填色":它画的是两条 lineColor 色的边线、中间留透明空隙(单图层就能画空心双线)。

九、路径动画(流光 / 跑马灯)

方案 A:lineDasharray 动画

let offset = 0;
function animate() {
  polyline.setLineDasharray([offset % 10, 4]);
  offset += 0.1;
  requestAnimationFrame(animate);
}
animate();

方案 B:用 symbol-placement: line 让图标沿线走(见 symbol/text-symbol)。

方案 C:createAnimateLineLayer 系列工厂一行创建动画图层:

const anim = vjmap.createAnimateLineLayer(map, path);   // path = [[x,y],...]
anim.startAnimation();
anim.setSpeed(2);          // 倍速
anim.stopAnimation();
anim.remove();             // source+layer 一起删
  • 返回 ICreateAnimateLayerResult,键面:{sourceId, layerId, startAnimation, stopAnimation, remove, updateData, updateImages, setSpeed, polyline};createAntPathAnimateLineLayer(蚂蚁线)/createArrowAnimateLineLayer(箭头流)额外带 createAnimateImages;createAnimateFillLayer 返回 polygon(非 polyline)。
  • 坑位:createAnimateSymbolLayer(map, path) 的 path 必须是点位数组 [[x,y],…]——传裸坐标 [x,y] 抛 Cannot use 'in' operator to search for 'points' in <number>(内部按数组迭代后对每个元素做 'points' in item 判定,数字元素直接崩)。
  • 坑位:createAnimateImages(options) 的 options 实必填——需 draw(ctx,w,h,opts) 或 drawFrame 回调,无参调用抛 Cannot read properties of undefined (reading 'draw');但 createAntPathAnimateImages/createArrowAnimateImages 可无参,各返 2 帧 ImageData。

方案 D:animateVectorLayer——给已存在的线/面/符号层做帧图案轮播:

map.addGeoJSONSource("src", createLineGeoJson(path));
map.addLineLayer("lay", "src", { lineColor: "#f60", lineWidth: 6 });
const anim = vjmap.animateVectorLayer(map, "lay", {
  animateImages: vjmap.createAntPathAnimateImages(),  // 帧图集(ImageData[])
  speed: 2,                                            // 倍速
  startAutoAnimation: true
}, /* layerType */ 0);                                 // 0=line(line-pattern) 1=fill(fill-pattern) 2=symbol(icon-image)
anim.startAnimation(); anim.setSpeed(4); anim.stopAnimation();
anim.remove();   // 恢复原 pattern,不删图层
  • 与方案 C 工厂不同:它不建层,第二参是已存在图层 id——层不在图上时内部 map.getPaintProperty(layerId,...) 读 getLayer→undefined 直接抛 Cannot read properties of undefined。返回 {startAnimation, stopAnimation, remove, updateImages, setSpeed}(没有 sourceId/layerId/updateData)。

十、修改 / 删除

polyline.setData(newFeatures);
polyline.setLineColor("#0af");
polyline.setLineWidth(5);
polyline.setLineDasharray([1, 2]);
polyline.setProperty("lineOpacity", 0.5);

polyline.hide();
polyline.show();
polyline.remove();

十一、事件

polyline.clickLayer(e => alert(e.features[0].properties.name));
polyline.hoverPopup(f => `<b>${f.properties.name}</b>`, { anchor: "bottom" });
polyline.hoverFeatureState();

十二、常见坑

  1. lineWidth 太细不显示 → < 0.5px 在高分屏可能消失;设 ≥ 1。
  2. lineGradient 无效 → source 未开 lineMetrics: true;或同时设了 linePattern(lineColor 不影响,只是被忽略)。
  3. 虚线密度感觉不对 → lineDasharray 单位 = 线宽倍数,不是像素。
  4. hover 无效 → feature 没 id 或 id 为 0(hoverFeatureState 用 if (featureId) 判断,0 被忽略)。封装类不透传 generateId(且 generateId 从 0 编号):FeatureCollection 须自带非 0 id;或传 [{points, properties}](自动 id = 序号 + 1);或先自建源(promoteId)再传 sourceId。
  5. 连线有毛刺 → lineJoin: "round" + lineCap: "round"。