基于echarts实现某些骚需求

758 阅读6分钟
阅读前提示:本文不会讲解ehcarts的API使用配置,要看请移步逛网文档,在此只提供一种关于某些特殊需求的快捷方便出效果的思路或建议。。。

做过基于echarts图表开发的小伙伴可能都有一种感觉,就是看文档或案例感觉啥都能做,但是看到UI妹子给过的图之后,瞬间感觉,这是什么鬼,案例上没有这种样子的啊,这就是理想和现实的差距。。。。在做过很多echarts图表开发之后,我个人感觉,对于基于echarts的开发一般都会经过几步:

  • 拿到需求
  • 分析需求
  • 寻找案例
  • 复制粘贴
  • 变成自己的

简单来说,其实是一个复制粘贴+不断查API修改代码的过程,这个过程看似无脑复制,其实也是有些技巧的。本文将通过在实际开发中遇到的两个案例,来剖析一下这个过程中的一些套路,希望再次遇到类似情况时有所启发。

拿到需求

  • 实现一个环形的分割占比图(称为需求1)
  • 实现一个柱形占比图(称为需求2)

分析需求

  • 需求1,实现一个环形的分割的这种图,这种相关的类似图其实我们还是经常见到的,给我第一印象就是芝麻信用分: 当然,芝麻评分这种是仪表板似的,但是原理相同。想到这,我们心中预期大概可能会需要用到仪表盘相关的图表变换,得到我们的需要。

  • 需求2,其实这就是一种柱形图,首先明确我们可能需要柱形图的变换来搞定。我们其实用echarts来实现柱形图的话,其实非常简单的,但是分析一下我们拿到的这个需求,大致分析其主要特殊性有以下三点:

    • 首先他是一个垂直方向的柱形图,他不光是要实现柱形图,而且这个柱形图还有个背景条
    • 其次数字都是标注在背景条的最右边的,同时每个柱形的维度名称标注在柱形上面
    • 最后,柱形图前三名的颜色要跟后面的有所区分

经过以上分析,首先在心目中大概明白了实现这种需求大概的技术方向,这是解决问题的第一步。有方向,接下来走就是了。

寻找案例

这步一般根据之前的需求信息和脑中形成解决问题的技术方向去寻找对应的现成的案例。当然,如果你对echarts使用非常熟悉,而且拿到需求之后,对解决方案已经了然于胸,那么可以直接跳过这步,开鲁就对了。

对于我来说,我去找案例,一般从三个方式入手:

  1. echarts官方的案例,入口在官网的顶部导航位置,这应该是大多数人看到的地方:
  2. 官网入口,民间各路好人开源的demo。这个地方从哪进入呢? 网址是:www.makeapie.com/explore.htm…

进入后的样子是这样的:

这个入口可能很多人就不是很熟悉了,只有像我这种一来就要把官方网站上所有文档包括常见问题都通读了一遍的认真人儿才会看到吧(😼😼😼😼😼😼)

  1. 搜索引擎,各种百度和Google搜索,这种技能其实无需多说,大部分人都会了。。。

上面三种途径,我只说第2种,其实如果你去看了其中的网站之后,你会发现,上面收录了很多很多江湖大侠们实现的一些小demo,而这些小demo,其实大多跟实际项目开发中遇到的各种图表需求相关,而别人解决过的问题,或许就是你现在需要的,而这,才是最重要的。

所以,在找案例这件事上,我的建议就是:优先去www.makeapie.com/explore.htm…里面逛逛,说不定有惊喜握。。。

对照我拿到的这两个需求来说,我进入上面的网站之后,随便都能找到类似的demo

比如分割圆环的: 实现我要柱形图的: 所以,到此,还有什么可说的呢?如果要把上面三种找案例的方式效率做一个排名,我觉得应该是这样的:2>1>3

对此的总结就是:找一个合适的案例,然后直接ctrl+c过来修改,它不香么?

复制粘贴

其实经过上面的步骤,找到案例之后,我想只要是个正常的人,应该都会想要copy。。。所以,这儿只说一点建议: 最好能基于原来的demo,直接修改代码,因为所见即所得,到基本符合你的需要之后,再把代码copy走,这样会好一点。

变成自己的

找到案例之后,修改到自己想要的效果,这一步可以看做是把别人的代码变成自己的了(看起来像是抄袭的感觉,谁说又不是呢?)

对照我上面的需求,找到对应的案例经过修改之后,改成我的需求代码如下:

  • 需求1
  const value = 15;//要显示的占比值
  const option = {
                // backgroundColor: '#1C2A5A',
                grid: {
                    top: '0',
                    left: '0',
                    bottom: '0',
                    right: '0',
                },
                series: [
                    {
                        type: 'gauge',
                        radius: '88%',
                        clockwise: false,
                        startAngle: '90',
                        endAngle: '-269.9999',
                        splitNumber: 20,
                        detail: {
                            offsetCenter: [0, -20],
                            formatter: ' ',
                        },
                        pointer: {
                            show: false,
                        },
                        axisLine: {
                            show: true,
                            lineStyle: {
                                color: [
                                    [
                                        (!value
                                            ? 0.1
                                            : value < 1
                                            ? 1
                                            : value >= 100
                                            ? 99.99
                                            : value) / 100,
                                        '#3A4988',
                                    ],
                                    [1, '#FCBA00'],
                                ],
                                width: 6,
                            },
                        },
                        axisTick: {
                            show: false,
                        },
                        splitLine: {
                            show: true,
                            length: 6,
                            lineStyle: {
                                color: '#1C2A5A',
                                width: 2,
                            },
                        },
                        axisLabel: {
                            show: false,
                        },
                    },
                    {
                        type: 'pie',
                        name: '内层细圆环',
                        radius: ['96%', '100%'],
                        hoverAnimation: false,
                        clockWise: false,
                        itemStyle: {
                            normal: {
                                color: '#3A4988',
                            },
                        },
                        label: {
                            show: false,
                        },
                        data: [100],
                    },
                ],
            };
  • 需求二
        const track = true; //是否有轨道
        const topColor = '#00B8FF';//排名前三的柱形颜色: {
        const lastColor = '#40E9B1';//排名后面的柱形颜色: {
        const valueSuffix = '万';//名称后缀
        const names = [
                '年收入第1名',
                '年收入第2名',
                '年收入第3名',
                '年收入第4名',
                '年收入第5名',
                '年收入第6名',
                '年收入第7名',
                '年收入第8名',
                '年收入第9名',
                '年收入第10名',
            ];
        const values = [7500, 7000, 6500, 6000, 5500, 5000, 4500, 4000, 3500, 3000];
        
            let lineY = [];
            let lineT = [];
            for (let i = 0; i < names.length; i++) {
                const data = {
                    name: names[i],
                    value: values[i],
                    barGap: '-100%',
                    itemStyle: {
                        show: true,
                        color: i < 3 ? topColor : lastColor,
                        barBorderRadius: 5,
                    },
                };
                lineY.push(data);
                //有轨道
                if (track) {
                    const data1 = {
                        value: values[0],
                        realValue: values[i],
                        itemStyle: {
                            color: '#2B3B6D',
                            barBorderRadius: 10,
                        },
                    };
                    lineT.push(data1);
                }
            }

            let option = {
                tooltip: {
                    trigger: 'item',
                    formatter: (p) => {
                        if (p.seriesName === 'total') {
                            return '';
                        }
                        return `${p.name}<br/>${p.value}万`;
                    },
                },
                grid: {
                    borderWidth: 0,
                    top: '1%',
                    left: '0%',
                    right: '10%',
                    bottom: '0%',
                },
                yAxis: [
                    {
                        type: 'category',
                        show: false,
                        inverse: true,
                        axisLine: { show: false },
                        axisTick: { show: false },
                        axisLabel: {
                            show: true,
                            inside: false,
                            verticalAlign: 'bottom',
                            lineHeight: '40',
                            textStyle: {
                                color: '#b3ccf8',
                                fontSize: '14',
                                fontFamily: 'PingFangSC-Regular',
                            },
                            formatter: function(val) {
                                return `${val}ee`;
                            },
                        },
                        splitArea: {
                            show: false,
                        },
                        splitLine: {
                            show: false,
                        },
                        data: values, 
                    },
                ],
                xAxis: {
                    type: 'value',
                    show: false,
                    axisTick: { show: false },
                    axisLine: { show: false },
                    splitLine: { show: false },
                    axisLabel: { show: false },
                },
                series: [],
            };
            //带名称的公用配置
            const nameBar = {
                name: 'bar',
                type: 'bar',
                zlevel: 1,
                barWidth: '6px',
                data: lineY,
                barGap: '-100%',
                label: {
                    color: '#b3ccf8',
                    show: true,
                    position: [0, '-18px'],
                    formatter: function(a) {
                        let str = '';
                        str = a.name;
                        return str;
                    },
                    rich: {
                        color: {
                            color: '#949FD5',
                            fontSize: 12,
                        },
                    },
                },
            };
            //有轨道
            if (track) {
                option.series = [
                    nameBar,
                    {
                        name: 'total',
                        type: 'bar',
                        zlevel: -1,
                        barGap: '-100%',
                        barWidth: '6px',
                        data: lineT,
                        legendHoverLink: false,
                        label: {
                            show: true,
                            position: 'right',
                            formatter: (a) => {
                                let str = '';
                                if (a.dataIndex < 3) {
                                    str = `{top|${a.data.realValue}${
                                        valueSuffix || ''}}{unit|${valueSuffix?'':'万'}}`;
                                } else {
                                    str = `{last|${a.data.realValue}${valueSuffix || ''}}{unit|${valueSuffix?'':'万'}}`;
                                }
                                return str;
                            },
                            rich: {
                                top: {
                                    fontSize: 14,
                                    color: topColor,
                                },
                                last: {
                                    fontSize: 14,
                                    color: lastColor,
                                },
                                unit: {
                                    color: '#949FD5',
                                    fontSize: 11,
                                },
                            },
                        },
                    },
                ];
            } else {
                //无轨道
                option.series = [
                    nameBar,
                    {
                        name: 'bar',
                        type: 'bar',
                        zlevel: 2,
                        barWidth: '6px',
                        data: lineY,
                        label: {
                            show: true,
                            position: 'right',
                            textStyle: {
                                fontSize: 14,
                            },
                            formatter: function(a) {
                                let str = '';
                                str = `${a.value}{unit|万}`;
                                return str;
                            },
                            rich: {
                                unit: {
                                    color: '#949FD5',
                                    fontSize: 11,
                                },
                            },
                        },
                    },
                ];
            }

上面的代码较简单,可以直接copy到项目中验证,相关变量做成参数,即可抽离出组件使用,在此不做赘述。。。

总结

  • 基于echarts的开发找到合适的案例非常关键
  • 找到demo之后基于文档的api进行修改,可以达到自己想要的效果
  • 想要修炼出深厚的内功,熟悉API文档是非常关键的

好了,就说这么多🐩🐩🐩🐩🐩🐩🐩