普通视图

发现新文章,点击刷新页面。
昨天 — 2025年4月2日首页

echarts 实现环形渐变

2025年4月2日 18:09

前言

最近产品在ecahrts官网上找到一个 饼图 想要实现这种从头到尾的渐变交互效果,一开始以为非常简单,echarts应该是提供了类似的配置项,知道做起来才发现,这其中没那么简单。

官网案例分析

官网例子中的渐变并不是echarts提供的配置项实现的,而是通过一张 图片 作为背景实现的渐变,所以一开始想着是先来实现一个渐变的饼图,然后通过多个饼图进行拼接来实现类似指针一样的效果,这样就能够实现自定义这个渐变的颜色,并且也很快就写出来一个demo

认识 Echarts 渐变色

在 echarts 的渐变色中,提供了三种类型,包括线性渐变(linear gradient)、径向渐变(radial gradient)和纹理填充(pattern)。

主要了解了一下 线性渐变 以及 径向渐变 的实现效果,在这之后,也意识到了一个严重的问题:通过echarts提供的颜色填充,貌似没办法实现案例里面这种从头到尾的渐变效果,通过线性渐变能够实现下面这种效果

image-20250402170925813.png

这种固定方向的渐变,但是并不符合我们的要求,

并且我也上网找了一些饼图渐变的案例,发现都是通过这种线性渐变来实现的,只不过会去计算这个渐变的角度,来实现类似从头到尾的渐变,但是一旦进度的幅度较大,就马上露馅了。

  • 例子

image-20250402171205454.png

image-20250402171307616.png

可以看到一旦我调大某一个区域的比例,就会发现最后的实现原理还是线性渐变,只不过动态的计算了角度,这种适合多个比例差不多的饼图,但是一旦有某个块比例过大,就还是会出现样式不够美观

奇思妙想

突然意识到,我们最终的目的是自定义这个圆环的起点和终点的颜色,这并不是非得用echarts提供的渐变功能,图片本身并没有问题,图片最大的限制就在于颜色是定好的,但是我们是不是可以让图片的颜色变成动态生成的?

当然可以!

与似乎,就有了下面的方案,通过 canvas 动态生成渐变背景,在讲这张背景图作为圆环的背景图,这样我们就能够实现自定义圆环的起点颜色和终点颜色了

canvas 生成渐变背景

canvas生成背景这个并不是什么难事,百度一下就能够找到类似的案例,然后丢给ai进行美化一下,修改参数变成自己想要的一个函数,我定义的是能够通过传入起点角度,起点颜色,终点颜色 图片大小 四个参数生成一张 base64 的图片

/**
 * 创建圆形渐变图片
 * @param startAngle 起始角度
 * @param startColor 起始颜色
 * @param endColor 结束颜色
 * @param size 大小
 * @returns
 */
export function createCircularGradientImage(startAngle = 0, startColor = '#fff', endColor = 'blue', size = 200) {
  // 创建一个canvas元素
  const canvas = document.createElement('canvas')
  // 设置canvas的宽度
  canvas.width = size
  // 设置canvas的高度
  canvas.height = size
  // 获取2D绘图上下文
  const ctx = canvas.getContext('2d')
  // 检查是否成功获取上下文
  if (!ctx) {
    throw new Error('ctx is null')
  }
  // 创建圆锥渐变
  // 参数:起始角度,圆心x坐标,圆心y坐标
  const gradient = ctx.createConicGradient(startAngle, size / 2, size / 2)
  // 添加渐变的起始颜色
  gradient.addColorStop(0, startColor)
  // 添加渐变的结束颜色
  gradient.addColorStop(1, endColor)
  // 设置填充样式并绘制矩形
  ctx.fillStyle = gradient
  ctx.fillRect(0, 0, size, size)
  // 将canvas转换为base64格式的图片数据
  const res = canvas.toDataURL('image/png')
  // 从DOM中移除canvas元素
  canvas.remove()
  // 返回生成的图片数据
  return res
}

最终我们能够得到一张类似这样的图片

image-20250402151912179.png

结果

接下来的步骤就简单了,参考官网的案例,我们只不过是替换了图片的来源,这样就能够通过传参获得一个自定义颜色的结果。

const _panelImageURL = createCircularGradientImage(0, '#E5E5FF', 'red')

最后的效果:

image-20250402155934106.png

至于文字颜色和阴影颜色,这些都有着很明显的配置项,这里就不做过多的赘述了,本文主要是分享一下通过canvas构造图片来实现渐变的这种思路

如果有大佬有更好的实现渐变的思路欢迎评论区留言!

昨天以前首页

echarts地图轮播markpoint-自用记录📝

作者 南茗啊
2025年4月1日 16:21

echarts地图轮播markpoint

正常添加echarts地图后,添加markpoint图层

 //引入echarts 注册地图 略过 只展示关键代码
option.series= [
            {
              // roam: true,
              name: '地图',
              type: 'map',
              id: 'mapData',
              map: 'china',
              data: this.outdata,  //无需在意 配合visualMap给地图区块添加颜色使用
              center: [95, 35],
              zoom: 1.5,
              z: 2,
              itemStyle: {
                borderColor: 'rgba(0,0,0,0.15)',
                borderWidth: 1.3,
                shadowColor: 'rgba(0,0,0,0.2)',
              },
              emphasis: {
                label: {
                  show: true,
                },
              },
            },
  //下方是markpoint代码 因为echarts官方已经不推荐使用markpoint 改为使用scatter
            {
              type: 'scatter',
              coordinateSystem: 'geo',
              //下方的symbol替换为需要展示的图标的base64编码即可
              symbol:
                'image://data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAAAXNSR0IArs4c6QAAA4VJREFUSEvNlV1oHUUUx/9nZnbv7s3dG2+akGoNGgp5UtDaEmqxNoIfXIUSYksrERP8Kj6KghSFvFQRTHzyIS0aWqQiIUUhHz4IxlDbBxUEK0UQCrYi9MamuTH3Y2d3jsy9DQZpbjcpBAeGhd2Z85v/mf85S9ikQZvEwf8P9ORXiy3kpnZp42yPockT8rcgLH0//lTztSRZuaWiA9NLbQtIH12uYlAzNRsGSAFCAY7Li55vxlKm8u7M3qDQCNgQ9NjE8o5q1Z+qaGytBZH1ycQgSYBCbfo+/sz6pfz0nsxPa8HWBO3/rNRxteydq4Z8tw1KBLC4Aas9GSxRB0qGH+DKFkc8/OWjdPlmsDVB+z7WZ/5eEr0kAbNyemK0NHFN1UKVwPa9hQoGK0ImMGfmnlB9iUH5U+HO60X1XVhhVyqCIaD9Do2hxwn3tdnIwC/zBkPnCH+UJOxhLFCkEbYF0Z7pHveH/8JuqqhnVB9dKsljiOp3oUSMsecMulodkM3hjfHrXxoDkwKhIJAgIAUEvn579pnUsUSgncPhaROpw2AAbLBjWwUn+n3ULmp16THj1UmNHwtO3SgKaAri8bn9zsFEoIc+NJMI8XQtZzrC3s4ihvtzIAtepYjBeHOqim9+dwFVd2GQNTPfPqvyiUC7hsPjcei8TMaAqxo5M4/Jd7Yi5cjVHFS1Qe/xCq6yB0gCKyCdNaNnD6kjiUDdH0TPx5E8aTQTRQZhoYBD3RHeOHwXXKduhlAbjEwtYPxCBm7WBQuCccDNW/TA1wfcU4lAu0cWW8Jy5gI03Qkw4uIywsI8HrhH45EHg1r6zl4M8fO1AE5rFtITsF4gj6+0txfv/6I3dz0RyC7qfi98TVfUR/buhTGIl8vQxSXEVQ0oCbc5A5FrAnkSwlpbMrxAH5l7yRtNXEd24b4hVmUnPhGxGEAEMDNgDGDqHUG4slakJGwJCPgZPSa7nFdmeyhaF6gOu+SV3Y4JE8u8sQBrOtt2VtqRdbuts3Q01dKp+mbyVF13r1vZcO/QJa9dbfskMvW6YgNQre3U+55sMqfT2csvzg52VjbcvVc2WmUVp+NkFMuDbJVZmENwgvDzXJf7QiMlKzFu+T/6F8Ze2eFPo4j6bOqUH014rap/dpAaKlk3yG7YPcJ+XNHvixQxkXrr/OtUbpSu1d8SK0oacMNmuF3AhlJ3O9BNS90/oxFMKoVN5+kAAAAASUVORK5CYII=',
              symbolSize: 30,
              symbolOffset: [0, '-50%'],
              label: {
                show: true,
                position: 'top',
                color: '#333333',
                fontSize: 14,
                fontWeight: 600,
                formatter: '{b}', //配合下方data中的name使用 展示name
                textBorderColor: '#ffffff',
                textBorderWidth: 2,
                textBorderType: 'solid',
              },
              emphasis: {
                scale: 1.2,
                label: {
                  fontSize: 18,
                },
              },
              select: {
                label: {
                  color: '#333333',
                  fontSize: 18,
                  fontWeight: 600,
                },
              },
              data: [
                {
                  name: '济南片区',
                  value: [117.2, 36.7],
                },
                {
                  name: '西南片区',
                  value: [104.065701, 30.659487],
                },
                {
                  name: '青岛片区',
                  value: [120.1, 36.4],
                },
                {
                  name: '华中片区',
                  value: [117.291321, 31.861125],
                },
                {
                  name: '华北片区',
                  value: [116.4, 39.9],
                },
                {
                  name: '华东片区',
                  value: [121.473701, 31.230393],
                },
                {
                  name: '华南片区',
                  value: [113.6, 23.1],
                },
                {
                  name: '东南片区',
                  value: [119.4543, 26.2875],
                },
                {
                  name: '中原片区',
                  value: [113.653427, 34.761125],
                },
              ],
            },
          ],

轮播代码如下:

思路是对当前高亮节点进行取消高亮操作,然后在高亮下一个节点

需要注意seriesIndex 可以通过在鼠标移入事件中添加打印信息获取

//该段代码在echarts初始化之后调用即可
startLunbo () {
        if (this.intervalId) {
          clearInterval(this.intervalId)
          this.intervalId = null
        }
        this.intervalId = setInterval(() => {
          this.myMapChart.dispatchAction({
            type: 'downplay',
            seriesIndex: 1,
            dataIndexInside: this.lunboId === 0 ? 8 : this.lunboId - 1, //和上面的代码片段中data的长度有关
          })
          this.myMapChart.dispatchAction({
            type: 'highlight',
            seriesIndex: 1,
            dataIndexInside: this.lunboId,
          })
          this.toolIdx = this.lunboId
          this.lunboId++
          if (this.lunboId > 8) { //和上面的代码片段中data的长度有关
            this.lunboId = 0
          }
        }, 2500)
      }

其中鼠标的移入移出事件 自行完成即可

echarts菜鸟踩坑——inverse 反向坐标轴

作者 抹茶san
2025年3月28日 22:13

感谢 UI 同学的鞭策,一周内迅速提升了我的 echarts 应用水平,为了不要在重复的地方跌倒两次,按照惯例还是要把踩过的坑记录下来。

需求:柱状图数据需要横着,并且从小到大排列 实际结果:使用横向柱状图,把柱状图数组数据从小到大排列时,柱子们是从大到小显示的,和我预想的情形是反的。虽然把数组反向很简单,但是通过echarts 的配置来实现更优。

image.png

通过配置 axis 的inverse属性,即可反向显示数据

yAxis. [inverse]

boolean

开启

是否是反向坐标轴。

Echarts series line图形markLine的使用

作者 霓虹伊
2025年3月27日 14:50

在一些特殊场景,可能会使用到markLine标线,这个标线不同于X轴的分割线。群:922473947 示例:

cafa202df8084237b6545e7e5c4441b2.png 上面示例中使用的图形是line,坐标系方式显示data: [[1,2],[3,4]]
官方实例中标线默认赋值是X轴index,例如一下代码

                symbol: 'none',
                lineStyle: {
                    type: 'solid',
                    width: 3
                },
                label: {
                    show: false
                },
                data: [{
                    name: 'Y1',
                    yAxis: 5,
                    itemStyle: {
                        color: '#000',
 
                    },
                }, {
                    name: 'X1',
                    xAxis: 5,
                    itemStyle: {
                        color: 'red'
                    },
                }, ]
            },

代码中配置的两个方向是Y轴下标5位置与X轴下标5位置,也就是说会显示在响应的下标位置,在实际应用中你markLine.data应该是遍历得到的数组,当你默认data数组的xAxis是你遍历X轴的每条数据的index,那么就是有多少条X轴类目,就显示多少条标线,但与此文要说的需求并不相同,如上面示例展示实际上是

红色与绿色标线都是使用的data[[1,2],[3,4]]作为series的data数据,在markLine中的data遍历series的data绑定的数组,然后取值绑定在markLine中data的每条xAxis的数据是series.data数据的如[0][0]也就是1。 如下面代码展示

      "name": "数据",
      "tooltip": {
        "show": false
      },
      "step": "start",
      "type": "line",
      "data": [
        [
          248,
          12.44
        ],
        [
          336,
          12.44
        ],
        [
          336,
          null
        ],
        [
          731,
          null
        ],
        [
          731,
          0.54
        ],
        [
          782,
          0.54
        ],
      ],
      "lineStyle": {
        "width": 4
      },
      "z": 998,
      "markLine": {
        "symbol": [
          "none",
          "none"
        ],
        "data": [
          {
            "xAxis": 248,
            "name": "12.44"
          },
          {
            "xAxis": 336,
            "name": "12.44"
          },
          {
            "xAxis": 336,
            "name": "null"
          },
          {
            "xAxis": 731,
            "name": "null"
          },
          {
            "xAxis": 731,
            "name": "0.54"
          },
          {
            "xAxis": 782,
            "name": "0.54"
          },
 
        ],
        "lineStyle": {
          "type": "solid",
          "width": 0.5
        },
        "label": {
          "show": false
        }
      }
    },

很显然会看到绑定的值,就能实现每个line的点位置都会出现标线。其中会看到series中的data坐标系存在null,请看第一张示例图中绿色line,可以看到存在断开,这也是需求的一部分,当然不能补空字符也可以‘’。反正不能为0,当然如果你的需求是线必须连着就可以补0 以下就是示例的全部代码

  "title": {
    "textStyle": {
      "color": "#000",
      "fontSize": 16,
      "fontWeight": "normal"
    },
  },
  "color": [
    "#4dbb27",
    "#f14646"
  ],
  "tooltip": {
    "trigger": "axis"
  },
  "xAxis": {
    "splitLine": {
      "show": false
    }
  },
  "yAxis": {},
  "grid": {
    "top": "9%",
    "left": "8%",
    "width": "88%",
    "height": "85%"
  },
  "series": [
    {
      "name": "数据",
      "tooltip": {
        "show": false
      },
      "step": "start",
      "type": "line",
      "data": [
        [
          248,
          12.44
        ],
        [
          336,
          12.44
        ],
        [
          336,
          ''
        ],
        [
          731,
          ''
        ],
        [
          731,
          0.54
        ],
        [
          782,
          0.54
        ],
      ],
      "lineStyle": {
        "width": 4
      },
      "z": 998,
      "markLine": {
        "symbol": [
          "none",
          "none"
        ],
        "data": [
          {
            "xAxis": 248,
            "name": "12.44"
          },
          {
            "xAxis": 336,
            "name": "12.44"
          },
          {
            "xAxis": 336,
            "name": "null"
          },
          {
            "xAxis": 731,
            "name": "null"
          },
          {
            "xAxis": 731,
            "name": "0.54"
          },
          {
            "xAxis": 782,
            "name": "0.54"
          },
 
        ],
        "lineStyle": {
          "type": "solid",
          "width": 0.5
        },
        "label": {
          "show": false
        }
      }
    },
    {
      "name": "限制",
      "tooltip": {
        "show": false
      },
      "step": "start",
      "type": "line",
      "data": [
        [
          72,
          18.78
        ],
        [
          157,
          18.78
        ],
        [
          157,
          27.22
        ],
        [
          204,
          27.22
        ],
        [
          204,
          40.37
        ],
        [
          240,
          40.37
        ]
      ],
      "lineStyle": {
        "width": 4
      },
      "z": 998,
      "markLine": {
        "symbol": [
          "none",
          "none"
        ],
        "data": [
          {
            "xAxis": 72,
            "name": "18.78",
            "lineStyle": {
              "width": 0.5,
              "color": "#f14646"
            }
          },
          {
            "xAxis": 157,
            "name": "18.78",
            "lineStyle": {
              "width": 0.5,
              "color": "#f14646"
            }
          },
          {
            "xAxis": 157,
            "name": "27.22",
            "lineStyle": {
              "width": 0.5,
              "color": "#f14646"
            }
          },
          {
            "xAxis": 204,
            "name": "27.22",
            "lineStyle": {
              "width": 0.5,
              "color": "#f14646"
            }
          },
          {
            "xAxis": 204,
            "name": "40.37",
            "lineStyle": {
              "width": 0.5,
              "color": "#f14646"
            }
          },
          {
            "xAxis": 240,
            "name": "40.37",
            "lineStyle": {
              "width": 0.5,
              "color": "#f14646"
            }
          }
        ],
        "lineStyle": {
          "type": "solid",
          "width": 0.5
        },
        "label": {
          "show": false
        }
      }
    }
  ]
}

喜欢可以点赞收藏

❌
❌