当前位置:   article > 正文

echarts间隔环形图、双间隔环形图的实现_echarts 间隙的圆环图

echarts 间隙的圆环图

在这里插入图片描述

首先上图看最终实现效果:

可以看到图中使用空白间隔把环形图表隔开,内部使用同样颜色不同透明度展示。

难点:

  1. 生成环形图空白间隔(使用border方式)。
  2. 生成环形图空白间隔(设置插入透明值方式)。
  3. 图例的展示与联动

解决:

  1. 这种方式无法添加内部透明环形图,因为内环与外环会产生间隔,无法实现紧贴的效果。如果要实现单个环形图的间隔,建议使用这种,代码可百度。
  2. 这种方式就是上图中实现的方式,通过插入透明的series值来实现。
  3. 重点:如果使用border实现图例就不用单独做处理。如果使用插入透明值的时候需要动态处理空白值,因为图例在开启和关闭时空白值依然存在。

实现思路:

  • 插入与series值同样的空白的值,最终的值就是这样。
const emptyValue = total*0.015
[
    {name:'机动车',value:134},
    {name:'',value:emptyValue},
    {name:'机动车1',value:134},
    {name:'',value:emptyValue},
    {name:'机动车2',value:134},
    {name:'',value:emptyValue},
    ...
]
//空白的值设置为固定的比例。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 接下来设置图例的交互
    给图表添加legendSelectChanged事件
    legendSelectChanged中能拿到图例状态的列表,我们通过这个状态的列表来判断

  • 过滤原列表,如果图例没有选中,就不插入空白值,反之亦然。
    同样,图例颜色也需要更新。

直接上代码

js文件

//gapPie.js
const colorList = [
    '#1555c2',
    '#4b98fa',
    '#a3d1ff',
    '#ffd653',
    '#fef1a3',
    '#fefce6',
    '#1ecc99',
    '#6be5b9',
    '#99f3ce',
    '#6456e2',
    '#b1a1ff',
    '#58d7db',
]
// 间隔 圆环图
const getSeresData = (data,total,selected) => {
    //设置默认selected
    const defaultSelected = {}
    data.map(item=>defaultSelected[item.name]=true)
    selected = { ...defaultSelected, ...selected };
    //获取选中的个数
    let selectedCount = Object.values(selected).filter(Boolean).length;
    //设置默认值
    const newData = []
    data.map((item) => {
        newData.push(item)
        //在选中的数据大于1的情况下添加空白间隔
        if(selected[item.name]&&selectedCount>1){
            newData.push({
                "value": total*0.015,
                "name": ""
            })
        }
    })
    return newData
}

const getSeriesColor = (data)=>{
    let colorIndex = 0; // 用于跟踪colorList中的颜色位置
    const resultColors = data.map(item => {
        if (item.name) {
            // 如果name不为空,使用当前颜色并增加索引
            return colorList[colorIndex++];
        } else {
            // 如果name为空,返回透明色
            return 'rgba(0,0,0,0)';
        }
    });
    return resultColors
}
const getTitleName = (titleName,total,lengthDetailShow) => {
    const graphic =  {
        elements: [
            {
                type: 'text',
                "left": lengthDetailShow?"11%":"19%",
                "top": "42%",
                style: {
                    text: total,
                    width:'120',
                    overflow:'truncate',
                    fontFamily:'DIN Alternate-Bold',
                    textAlign: 'center',
                    fill: '#E6EAF0 ',
                    fontSize: '32'
                },
            },
            {
                type: 'text',
                "left": lengthDetailShow?"11%":"19%",
                "top": "57%",
                style: {
                    text: titleName,
                    fontFamily:'FZLanTingHeiS-DB-GB-Re',
                    width:'120',
                    overflow:'truncate',
                    textAlign: 'center',
                    fill: '#A5ADBA ',
                    fontSize: '14'
                },
            }
        ]
    }
    return titleName?graphic:{elements:[]}
}
export const legendSelectChanged = (chartRef,event)=>{
    const {data} = chartRef.getOption()

    // 计算总值,只计算被勾选的数据
    const total = data.reduce((sum, item) => {
        // 如果select中对应的name为true,则累加它的value
        if (event.selected[item.name]) {
            return sum + item.value;
        }
        return sum;
    }, 0); // 初始值为0
    // 获取新的series数据
    const newData = getSeresData(data,total,event.selected)
    // 获取新的颜色
    const seriesColor = getSeriesColor(newData)
    // 缓存颜色函数以避免重复定义
    const colorFunction = params => seriesColor[params.dataIndex];
    //更新数据
    chartRef.setOption({
        series: [{
            data: newData,
            "itemStyle": {
                color: colorFunction,
            },
        },{
            data: newData,
            "itemStyle": {
                color: colorFunction,
            },
        }]
    });
}
/**
 * 图表参数配置
 *
 * @param {Object} data - 图表所需数据
 * @param {Object} config - 图表的配置项
 * @param {string} config.titleName -图表中心的文字信息
 * @param {boolean} [config.lengthDetailShow] - 图例是否展示详细信息
 * @param {boolean} [config.isLegendNumClick] - 图例数字是否可点击(用来判断修改颜色)
 * @returns {ChartOptions} 返回图表配置
 */
export default (data = [],config = {}) => {
    const total = data.reduce((total, item) => {
        return total + item.value
    }, 0)
    const {titleName,lengthDetailShow,isLegendNumClick} = config
    return  {
        data,
        "legend": {
            // selectedMode:false,
            type: 'scroll',
            itemWidth: '10',
            itemHeight: '10',
            borderRadius: '2',
            icon: 'roundRect',
            y: 'center', // 图例垂直居上
            left: lengthDetailShow?'50%':'58%',
            height: data.length>=9?'90%':'100%',
            width: '100%',
            orient: 'vertical',
            align: 'auto',
            itemGap: '21',
            textStyle: {
              fontSize: '14',
              color: '#C3CED5',
              fontFamily:
                'font-family: Source Han Sans CN-Regular, Source Han Sans CN',
              rich: {
                name: {
                  verticalAlign: 'right',
                  align: 'left',
                  width: '80',
                  height: '20',
                  fontSize: '14',
                  color: '#C3CED5',
                },
                value: {
                  align: 'left',
                  color: isLegendNumClick?'#4B98FA':'#C3CED5',
                  fontSize: '14',
                },
                rate: {
                  align: 'left',
                  width: '50',
                  fontSize: '14',
                  color: '#C3CED5',
                },
              },
            },
            pageTextStyle:{
                color:'#C3CED5'
            },
            pageButtonItemGap: '20',
            pageButtonGap:'10',
            pageButtonPosition: 'end', // 按钮在图例的末尾位置,即底部
            pageIcons: {
                vertical: [
                    'image://data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGcgaWQ9IiYjMjI4OyYjMTg2OyYjMTY0OyYjMjI4OyYjMTg3OyYjMTUyOyYjMjMyOyYjMTc1OyYjMTgwOyYjMjMwOyYjMTUyOyYjMTQyOyI+CjxnIGlkPSJpY29uLSYjMjI4OyYjMTg0OyYjMTM5OyYjMjMwOyYjMTM5OyYjMTM3OyYjMjI5OyYjMTc3OyYjMTQ5OyYjMjI5OyYjMTg4OyYjMTI4OyYjMjI5OyYjMTY0OyYjMTM1OyYjMjI4OyYjMTg3OyYjMTg5OyA1Ij4KPHJlY3QgeD0iMTYiIHk9IjE2IiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHJ4PSIyIiB0cmFuc2Zvcm09InJvdGF0ZSgtMTgwIDE2IDE2KSIgc3Ryb2tlPSIjMjY0MjdFIiBzdHJva2UtbWl0ZXJsaW1pdD0iMCIgc3Ryb2tlLWxpbmVqb2luPSJiZXZlbCIvPgo8ZyBpZD0iaWNvbi0mIzIyODsmIzE4NDsmIzEzOTsmIzIzMDsmIzEzOTsmIzEzNzsmIzIyOTsmIzE3NzsmIzE0OTsmIzIyOTsmIzE4ODsmIzEyODsiPgo8cmVjdCBpZD0iJiMyMzE7JiMxNTk7JiMxNjk7JiMyMjk7JiMxODk7JiMxNjI7IiBvcGFjaXR5PSIwLjAxIiB4PSIxNiIgeT0iMTYiIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdHJhbnNmb3JtPSJyb3RhdGUoLTE4MCAxNiAxNikiIGZpbGw9IiM3NTdEOEIiLz4KPHBhdGggaWQ9IiYjMjMyOyYjMTgzOyYjMTc1OyYjMjI5OyYjMTkwOyYjMTMyOyIgZD0iTTExLjA1NjcgMTAuNTI2NEw4IDcuNDY5N0w0Ljk0MzMzIDEwLjUyNjRMNCA5LjU4MzAzTDggNS41ODMwM0wxMiA5LjU4MzAzTDExLjA1NjcgMTAuNTI2NFoiIGZpbGw9IiNBNUJCRkEiLz4KPC9nPgo8L2c+CjwvZz4KPC9zdmc+Cg==',
                    'image://data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGcgaWQ9IiYjMjI4OyYjMTg2OyYjMTY0OyYjMjI4OyYjMTg3OyYjMTUyOyYjMjMyOyYjMTc1OyYjMTgwOyYjMjMwOyYjMTUyOyYjMTQyOyI+CjxnIGlkPSJpY29uLSYjMjI4OyYjMTg0OyYjMTM5OyYjMjMwOyYjMTM5OyYjMTM3OyYjMjI5OyYjMTc3OyYjMTQ5OyYjMjI5OyYjMTg4OyYjMTI4OyYjMjI5OyYjMTY0OyYjMTM1OyYjMjI4OyYjMTg3OyYjMTg5OyA0Ij4KPHJlY3Qgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiByeD0iMiIgc3Ryb2tlPSIjMjY0MjdFIiBzdHJva2UtbWl0ZXJsaW1pdD0iMCIgc3Ryb2tlLWxpbmVqb2luPSJiZXZlbCIvPgo8ZyBpZD0iaWNvbi0mIzIyODsmIzE4NDsmIzEzOTsmIzIzMDsmIzEzOTsmIzEzNzsmIzIyOTsmIzE3NzsmIzE0OTsmIzIyOTsmIzE4ODsmIzEyODsiPgo8cmVjdCBpZD0iJiMyMzE7JiMxNTk7JiMxNjk7JiMyMjk7JiMxODk7JiMxNjI7IiBvcGFjaXR5PSIwLjAxIiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIGZpbGw9IiM3NTdEOEIiLz4KPHBhdGggaWQ9IiYjMjMyOyYjMTgzOyYjMTc1OyYjMjI5OyYjMTkwOyYjMTMyOyIgZD0iTTQuOTQzMzMgNS40NzM2M0w4IDguNTMwM0wxMS4wNTY3IDUuNDczNjNMMTIgNi40MTY5N0w4IDEwLjQxN0w0IDYuNDE2OTdMNC45NDMzMyA1LjQ3MzYzWiIgZmlsbD0iI0E1QkJGQSIvPgo8L2c+CjwvZz4KPC9nPgo8L3N2Zz4=',
                ]
            },

            data: data.map((item) => item.name),
            formatter: function (name) {
              let tarValue
              for (var i = 0; i < data?.length; i++) {
                if (name === data?.[i]?.name) {
                  tarValue = data?.[i]?.value
                }
              }
      
              let p = Math.round((tarValue / total) * 100)
              const detail = '{rate|      ' + p+'%' + '}' + '{value|      ' + tarValue + '}'
              return '{name| ' + name + '}' + (lengthDetailShow?detail:'')
            },
          },
          "tooltip": {
            // "trigger": "axis",
            "backgroundColor": "rgba(130,174,255,0.2)",
            "borderWidth": 0,
            "className": "tooltip-back-bar",
            "textStyle": {
                "color": " #E8F3FF",
                "fontSize": '12',
                "fontFamily": "Source Han Sans CN-Bold, Source Han Sans CN",
                "fontWeight": "bold"
            },
            "axisPointer": {
                "lineStyle": {
                    "type": "solid",
                    "color": "rgba(54, 134, 255, 1)"
                }
            }
        },
        graphic: getTitleName(titleName,total,lengthDetailShow),
        "series": [{
                "name": "",
                "type": "pie",
                "center": [
                    lengthDetailShow?"22%":"30%",
                    "50%"
                ],
                "radius": [
                    '85',
                    '95'
                ],
                tooltip:{
                    show:true,
                    formatter: function (params) {
                        if(params.name){
                            return params.marker + params.name + '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;' + params.value
                        }
                    }
                },
                "avoidLabelOverlap": true,
                "label": {
                    "show": false
                },
                "itemStyle": {
                    color: params=>{
                        const seriesData = getSeresData(data,total)
                        const seriesColor = getSeriesColor(seriesData)
                        return seriesColor[params.dataIndex]
                    }
                    // color: (params) => {
                    //     const newColorList = []
                    //     colorList.map(color=>{
                    //         newColorList.push(color,'rgba(0,0,0,0)')
                    //     })
                    //     return newColorList[params.dataIndex]
                    // },
                    // borderRadius: 0,
                    // borderColor: '#fff',
                    // borderWidth: 5
                    // borderWidth: 5, // 设置环形图的间隔宽度
                    // borderColor: '#13264f' // 设置间隔颜色为透明
                },
                "emphasis": {
                    "label": {
                        "show": false
                    }
                },
                "labelLine": {
                    "show": false
                },
                "data": getSeresData(data,total)
            },
            {
                "name": "",
                "type": "pie",
                "center": [
                    lengthDetailShow?"22%":"30%",
                    "50%"
                ],

                "radius": [
                    '65',
                    '85'
                ],
                "avoidLabelOverlap": true,
                "labelLayout": {
                    "hideOverlap": false
                },
                "label": {
                    "show": false
                },
                tooltip:{
                    show:true,
                    formatter: function (params) {
                        if(params.name){
                            return params.marker + params.name + '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;' + params.value
                        }
                    }
                },
                "itemStyle": {
                    // color: (params) => {
                    //     const newColorList = []
                    //     colorList.map(color=>{
                    //         colorList.map(color=>{
                    //             newColorList.push(color,'rgba(0,0,0,0)')
                    //         })
                    //     })
                    //     return newColorList[params.dataIndex]
                    // },
                    color: params=>{
                        const seriesData = getSeresData(data,total)
                        const seriesColor = getSeriesColor(seriesData)
                        return seriesColor[params.dataIndex]
                    },
                    opacity: 0.1,
                    // borderWidth: 5, // 设置环形图的间隔宽度
                    // borderColor: '#13264f' // 设置间隔颜色为透明
                },
                "emphasis": {
                    "disabled": true,
                    "label": {
                        "show": false
                    }
                },
                "labelLine": {
                    "show": false
                },
                "data": getSeresData(data,total)
            }
        ]
    }
}
  • 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
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334

vue中使用

<template>
<v-echarts :option="gapChart" 
ref="chartRef"
@legendSelectChanged="handleLegendChanged"></v-echarts>
</template>
<script setup>
import { ref } from 'vue'
const chartRef = ref(null)
import gapPie, { legendSelectChanged } from '@/components/chart/chartOptions/pie/gapPie'

const handleLegendChanged = (event)=>{
    legendSelectChanged(chartRef,event)
}
gapChartLegend.value = gapPie([{
    "value": 1996,
    "name": "小型车"
},
{
    "value": 1270,
    "name": "公交车"
},
{
    "value": 1170,
    "name": "渣土车"
},
], {
    titleName: '车辆总数',
    lengthDetailShow: true,
    isLegendNumClick: true
})
</script>
  • 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

附上demo地址:
https://faintout.github.io/auto-echarts

代码地址:
https://github.com/faintout/auto-echarts

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/105450
推荐阅读