Jinuss's blog Jinuss's blog
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 《Vue》
    • 《React》
    • 《Git》
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

东流

前端可视化
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 《Vue》
    • 《React》
    • 《Git》
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • React

  • Vue

  • JavaScript文章

  • 学习笔记

  • openlayers

  • threejs

  • MapboxGL

    • MapboxGL加载离线字体
    • MapboxGL中要素自定义闪烁动画
      • 需求描述
      • 解决方案
        • Openlayers
        • Mapbox GL
        • 动态修改样式配置
        • 动态修改要素属性
      • 总结
    • Mapbox GL 地图选点偏移问题深度解析与解决方案
  • 工具

  • 源码合集

  • 前端
  • MapboxGL
东流
2025-02-17
目录

MapboxGL中要素自定义闪烁动画

# 需求描述

在面板上有一标记列表,要求点击每列就跳转到地图上该标记对应的位置,并实现该标记闪烁效果,用于提高用户交互体验。

# 解决方案

# Openlayers

在 Openlayers 中,无论标记的几何对象是点、线,还是面,每个标记都可以视为一个feature。可以先获取点击feature的style,记为A_style,然后定义feature的第二种style样式,记为B_style。然后通过定时器隔一段时间调用feature.setStyle(A_style/B_style)设置标记feature的样式,实现闪烁效 果。

# Mapbox GL

不同于 Openlayers,Mapbox GL 中没有如此丰富实用的 API 进行设置或者获取feature的样式。Mapbox GL 中样式是在配置文件中图层属性中预先定义的,而且点线面的样式定义也不一样,可以在一个图层源中,但是一般情况下会分属不同的图层。

因此如果想在 Mapbox GL 中实现要素的动态样式修改即闪烁效果,可以考虑从两方面入手。一是动态修改配置的样式,二则是动态修改要素feature的属性。本质上两者是殊途同归,Mapbox GL 的要素显示的样式与其属性可以关联。

# 动态修改样式配置

如下是图层的样式配置,定义了图层 ID 为draw-line时,过滤类型,定义线条的样式颜色为蓝色(blue)和宽度为4px。

const styles = {
  layers: [
    {
      id: "draw-line",
      type: "line",
      filter: ["==", "$type", "LineString"],
      paint: {
        "line-color": "blue", // 线条颜色
        "line-width": 4, // 线条宽度
      },
    },
  ],
};
1
2
3
4
5
6
7
8
9
10
11
12
13

如下代码是封装的一个函数,接受参数为:地图实例map、图层 IDlayerID、线要素 IDlineId、闪烁次数maxBlinks、闪烁间隔时间interval。

function blinkLine({ map, layerId, lineId, maxBlinks = 10, interval = 500 }) {
  var blinkCount = 0;
  var isVisible = true;
  var blinkInterval = setInterval(function () {
    if (blinkCount < maxBlinks) {
      // 每次闪烁切换透明度
      let color = isVisible ? "red" : "blue";
      if (!map.getLayer(layerId)) {
        clearInterval(blinkInterval);
        return;
      }
      map.setPaintProperty(layerId, "line-color", [
        "case",
        ["==", ["get", "id"], lineId],
        color,
        "blue",
      ]);
      isVisible = !isVisible; // 切换可见性

      // 增加计数器
      blinkCount++;
    } else {
      // 达到最大闪烁次数后清除定时器
      clearInterval(blinkInterval);
      if (!map.getLayer(layerId)) {
        clearInterval(blinkInterval);
        return;
      }
      map.setPaintProperty(layerId, "line-color", "blue");
    }
  }, interval); // 每500毫秒切换一次
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

上述例子主要就是在定时器中,通过map.setPaintProperty方法修改指定图层指定线条的样式。

# 动态修改要素属性

如下代码是定义图层的样式,主要是 Mapbox GL 中样式配置的case语法,["==",["get","selected"],true]会从图层LAYERS.SHEETLAYER中的所有要素中获取selected属性,当该属性值为true时,会使用colors.selected.fill样式,否则使用colors.unset.fill样式。

export const colors = {
  unset: { fill: "rgb(200,200,0)", stroke: "rgb(220, 243, 9)" },
  doing: { fill: "rgb(242, 127, 12)", stroke: "rgba(242, 127, 12,1)" },
  complete: { fill: "rgb(84, 186, 111)", stroke: "rgba(84, 186, 111,1)" },
  selected: { fill: "rgb(200,100,100)", stroke: "rgba(240, 6, 6, 0.5)" },
  disabled: { fill: "rgb(70,67,67)", stroke: "rgba(70,67,67,0.375)" },
};

export const getMapSheetLayer = ({ sourceName }) => {
  return {
    id: LAYERS.SHEETLAYER,
    type: "fill",
    source: sourceName,
    paint: {
      "fill-color": [
        "case",
        ["==", ["get", "selected"], true],
        colors.selected.fill,
        ["==", ["get", "status"], "doing"],
        colors.doing.fill,
        ["==", ["get", "status"], "complete"],
        colors.complete.fill,
        ["==", ["get", "disabled"], true],
        colors.disabled.fill,
        colors.unset.fill,
      ],
      "fill-opacity": 0.5,
      "fill-out-color": [
        "case",
        ["==", ["get", "selected"], true],
        colors.selected.stroke,
        ["==", ["get", "status"], "doing"],
        colors.doing.stroke,
        ["==", ["get", "status"], "complete"],
        colors.complete.stroke,
        ["==", ["get", "disabled"], true],
        colors.disabled.stroke,
        colors.unset.stroke,
      ],
    },
  };
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

如下代码是获取图层中的所有要素,然后动态修改要素的selected属性值,然后执行getSource(SOURCE_NAME).setData(geoJson)更新图层源,进而更新样式。

const getAllFeatures = () => {
  const data = map.value.getSource(SOURCE_NAME)?._data;
  if (!data) {
    return { features: [] };
  }
  return { features: data.features };
};

const blinkFeature = ({ mesh, selected }) => {
  const { features } = getAllFeatures();
  if (features && features.length) {
    const list = features.filter((f) => f.properties.name == mesh);
    if (list && list.length) {
      const feature = list[0];
      const mesh = feature.properties.name;
      meshList.value = [...meshList.value].map((i) => {
        if (i.mesh == mesh) {
          i.selected = !selected;
        }
        return i;
      });
      let geoJson = {
        type: "FeatureCollection",
        features: features.map((feature) => {
          const { name } = feature.properties;
          if (name == mesh) {
            feature.properties.selected = !selected;
          }
          return feature;
        }),
      };
      map.value.getSource(SOURCE_NAME).setData(geoJson);
    }
  }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 总结

本文介绍了在 Openlayers 和 Mapbox GL 中实现地图标记闪烁效果的两种技术方案:

  • Openlayers:通过动态修改 feature 的样式实现闪烁效果。
  • Mapbox GL:通过动态修改样式配置或要素属性实现闪烁效果。

两种方案各有优缺点: Openlayers 提供了丰富的 API,可以直接操作 feature 的样式,实现起来较为简单。Mapbox GL 的样式配置更为灵活,但需要通过修改样式或属性来触发更新,实现稍显复杂。如果项目中使用的是 Openlayers,推荐直接操作 feature 的样式;如果使用 Mapbox GL,则可以根据实际情况选择动态修改样式或属性。

通过实现地图标记的闪烁效果,可以显著提升用户交互体验,帮助用户更直观地定位目标位置。

编辑 (opens new window)
上次更新: 2025/02/24, 07:29:12
MapboxGL加载离线字体
Mapbox GL 地图选点偏移问题深度解析与解决方案

← MapboxGL加载离线字体 Mapbox GL 地图选点偏移问题深度解析与解决方案→

最近更新
01
GeoJSON
05-08
02
Circle
04-15
03
CircleMarker
04-15
更多文章>
Theme by Vdoing | Copyright © 2024-2025 东流 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式