关于封装echarts的那些事


前言

每个开发者在制作图表时都需要从头到尾书写一遍完整的option配置,十分冗余。在同一个项目中,各类图表设计十分相似,甚至是相同,没必要一直做重复工作,可能有一些开发者忘记考虑echarts更新数据的特性,以及窗口缩放时的适应问题。这样导致数据更新了echarts视图却没有更新,窗口缩放引起echarts图形变形问题,这就需要我们程序猿发动偷懒的特技啦!QAQ


我希望这个echarts组件能设计成什么样

  • 业务数据和样式配置数据分离,我只需要传入业务数据就行了
  • 可以自定义一套需要的图表样式进行集中管理,或者可以直接引用echart官网下载的主题
  • 不会因为缩放出现变形问题,而是能很好地自适应
  • 有时候某个图表的样式可能有点不一样,希望能保留自己配置样式的灵活性
  • 无论传入什么数据指定图表类型就能正确地更新视图
  • 如果我传入的数据为空,能展示一个空状态

提示:echarts官网地址          自定义主题下载

一、对使用echarts需要提前知道的知识

option = {
    color: ['#3398DB'], // 图表色系
    tooltip: {
        trigger: 'axis',
        axisPointer: {            // 坐标轴指示器,坐标轴触发有效
            type: 'shadow'        // 默认为直线,可选为:'line' | 'shadow'
        }
    },
    grid: { // canvas容器内边距
        left: '3%',
        right: '4%',
        bottom: '3%',
        containLabel: true // 是否允许某些情况超出面板,默认false:允许
    },
    xAxis: [ // 横坐标轴
        {
            type: 'category',
            data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
            axisTick: {
                alignWithLabel: true
            }
        }
    ],
    yAxis: [ //纵坐标轴
        {
            type: 'value',
            name: 'y轴名称'
        }
    ],
    series: [ //不同类型的数据结合
        {
            name: '直接访问',
            type: 'bar', //此数据对象对应的图表类型,可以为line, pie等
            barWidth: '60%',
            data: [10, 52, 200, 334, 390, 330, 220]
        }
    ]
};

1.

观察echart不同类型的图表,如上图,我们会发现xAxis、yAxis、series都是数组,那么我们就可以使他们都变成两条数据即 两个相同或不同的横坐标轴、两个相同或不同的纵坐标轴、两个相同或不同的图表类型 进行任意搭配

2.

我们把他们的样式和数据拆分来看时(例如:饼状图、柱状图、折线图),你会发现用同一个’option’ 我们仅需要改变series中type属性即可它在不同形状之前切换(当然啦,饼状图并没有横纵坐标轴~)

在这里插入图片描述
3.图表初始化

(1)let myChart = echarts.init(dom, theme, opts)

(dom: HTMLDivElement|HTMLCanvasElement, theme?: Object|string, opts?: {
    devicePixelRatio?: number,
    renderer?: string,
    width?: number|string,
    height?: number|string
}) => ECharts
dom:实例容器,一般是一个具有高宽的div元素。
theme:应用的主题。可以是一个主题的配置对象,也可以是使用已经通过 echarts.registerTheme 注册的主题名称。
opts:附加参数。附加选项见 图表初始化

扫描二维码关注公众号,回复: 16837629 查看本文章

(2)myChart.setOption(option, merge, updates);

option:图表数据 Object
merge:是否和上次设置的option进行合并? boolean, 默认false即合并
updates:设置完option后是否不立即更新图表? boolean,默认false即立即更新

(3)echart4 配置属性:dataset数据集
ECharts 4 开始支持了 数据集(dataset)组件用于单独的数据集声明,从而数据可以单独管理,被多个组件复用,并且可以自由指定数据到视觉的映射。这在不少场景下能带来使用上的方便。

关于 dataset 的详情,请参见教程

二、开始封装

1.封装思路及使用

(1) 除了option中最基础的框架,我们把样式的设置都尽量放在我们自定义的主题文件中 ‘mysetTheme.js’
(2) 数据组建的格式为:
在这里插入图片描述
其中 group存储类型名称(图例名),name存储xAxis.data数据(x轴名称),value存储 x轴对应的数据。
(3) 比较特别的情况
我们需要两个y轴时就需要在每条数据中指定右侧y轴对应哪些数据(默认不指定的情况下为左侧y轴)即添加‘yAxisIndex: 1’。此时数据格式应如下:
在这里插入图片描述
如果有两个不同的group都指定了‘yAxisIndex: 1’ 那么右侧的y轴会对应两个不同的图表。

(4) 为了便于以后个性化扩展,我们可以定义不同的option放在EchartsOption对象中,我们在使用时就可以向下方这样去获取不同的option

/**
 * 饼图
 * @param title : 标题<br>
 * @param subtext :副标题<br>
 * @param data : json 数据
 * @param radiusArr : array [内环百分比,外环百分比],不指定为普通饼图
 */
var option = MyEcharts.EchartsOption.pie("饼状图", "单位(人)", data,["48%","68%"]);
/**
 * 折线图
 * @param title : 标题<br>
 * @param subtext :副标题<br>
 * @param data : json 数据
 */
var option = MyEcharts.EchartsOption.Line("折线图", "单位(人)", data);
/**
 * 参数说明同折线图
 */
var option = MyEcharts.EchartsOption.bar("柱状图", "单位(人)", data);
/**
 * 参数说明同折线图
 */
var option = MyEcharts.EchartsOption.acrossBar("横向柱状图", "种类数(份)", data);
/**
 * 双y轴/混搭
 * @param title : string 标题
 * @param subtext : string 副标题
 * @param data : json 数据
 * @param type : Array 或 string,数组时需要和图例个数相对应,字符串时为统一类型 **注意:要想双y轴,type不管为哪种类型时都需要在数据中指定AxisIndex的值**
 */
var option = MyEcharts.EchartsOption.doubleYMixUp("混搭or双y轴", "种类数(份)", data, ['line', 'bar', 'line']);
var option = MyEcharts.EchartsOption.Radar("雷达图", "副标题名称", data);
var option = MyEcharts.EchartsOption.Funnel("漏斗图", "副标题名称", data);

(5) 获取到option后就可以像正常使用echart一样,指定id进行初始化了

 /**
  * @param option : option
  * @param echartId : 具备高宽的div元素id 
  */
MyEcharts.initChart(option, "main");

2.灵活配置

当我们不想改变EchartsOption中option的配置又想添加自己的样式时,我们可以使用以下不同的方式
(1) 使用initChart.setOption()指定新的配置

var data = [{
    
     name: '男生', value: 10 },{
    
     name: '女生', value: 20 }];
var option = MyEcharts.EchartsOption.pie("男女人数统计", "单位(人)", data);
var initChart = MyEcharts.initChart(option, "main");
//重新定义样式
var options = {
    
    
    color:["#FDB157","#3498DB"],
    legend : {
    
    
        orient: 'vertical', //垂直:vertical; 水平 horizontal
        right:'right',
    },
    series:[{
    
    
        radius : '55%', //圆的大小
        center : ['50%', '60%'],//位置居中
    }]
};
initChart.setOption(options);

(2) 直接对option进行赋值(不推荐)

var data = [{
    
     name: '男生', value: 10 },{
    
     name: '女生', value: 20 }];
var option = MyEcharts.EchartsOption.pie("男女人数统计", "单位(人)", data);
//重新定义样式
option.color = ["#FDB157","#3498DB"];
option.legend = {
    
    
    orient: 'vertical', //垂直:vertical; 水平 horizontal
    right:'right',
}
option.series[0] = {
    
    
    radius : '55%', //圆的大小
    center : ['50%', '60%'],//位置居中
}
var initChart = MyEcharts.initChart(option, "main");

(3) 对于非数据的配置,如:色系,title的颜色或排列位置的公用样式推荐都在mysetTheme.js中配置,如下

/**
 * echart自定义主题
 * Author:  abner
 * Date: 2020-12-25
 * 注意:主题的优先级比setOption低
 */
let myTheme = {
    
    
    // 全图默认背景
    // backgroundColor: 'rgba(0,0,0,0)',
    // 全图文字
    "textStyle": {
    
    
        color: '#fff',
        fontFamily: 'Microsoft YaHei UI',
        fontSize: 12,
    },
    // 默认色板
    "color": ['#838CFF', '#2AE3FF', '#FA7332', '#D797FF', '#fa2c7b', '#ff38e0', '#ffa235', '#04c5f3', '#0066fe', '#8932a5', '#c90444', '#cb9bff', '#434348', '#90ed7d'],
    //标题
    "title": {
    
    
        x: 'center',	//位置默认居中
        textStyle: {
    
    
            fontFamily: 'Microsoft YaHei UI',
            fontSize: 14,
            color: '#fff' // 主标题文字颜色
        },
        subtextStyle: {
    
    
            color: '#aaa'  // 副标题文字颜色
        }
    },
    // @图例
    "legend": {
    
    
        type: 'plain', //plain:普通图例 'scroll':可滚动翻页的图例。当图例数量较多时可以使用。
        orient: 'horizontal', //垂直 vertical | 水平 horizontal
        left: 'left',	//位置默认左
        // bottom: '0',
        textStyle: {
    
    
            color: '#fff'  // 图例文字颜色
        }
    },
    // @工具栏  此配置无法起效,必须在option中配置
    // "toolbox": {
    
    
    //     show: true, // 默认显示
    //     feature: {
    
    
    //         dataZoom: {
    
    
    //             yAxisIndex: 'none'
    //         },
    //         dataView: { readOnly: false },
    //         magicType: { type: ['line', 'bar'] },
    //         restore: {},
    //         saveAsImage: {}
    //     }
    // },
    // @纵轴
    "categoryAxis": {
    
    
        "axisLine": {
    
    
            "show": true,
            "lineStyle": {
    
    
                "color": "#008acd"
            }
        },
        "axisTick": {
    
     // 刻度线
            "show": true,
            "lineStyle": {
    
    
                "color": "#fff"
            }
        },
        "axisLabel": {
    
     // 刻度值
            "show": true,
            "textStyle": {
    
    
                "color": "#fff"
            }
        },
        "splitLine": {
    
     // 坐标轴在 grid 区域中的分隔线。默认数值轴(横向)显示,类目轴(纵向)不显示。
            "show": false,
            "lineStyle": {
    
    
                "color": [
                    "#eee"
                ]
            }
        },
        "splitArea": {
    
     // 坐标轴在 grid 区域中的分隔区域,默认不显示。
            "show": false,
            "areaStyle": {
    
    
                "color": [
                    "rgba(250,250,250,0.3)",
                    "rgba(200,200,200,0.3)"
                ]
            }
        }
    },
    // @横轴
    "valueAxis": {
    
    
        "axisLine": {
    
    
            "show": true,
            "lineStyle": {
    
    
                "color": "#008acd"
            }
        },
        "axisTick": {
    
     // 刻度线
            "show": true,
            "lineStyle": {
    
    
                "color": "#fff"
            }
        },
        "axisLabel": {
    
     // 刻度值
            "show": true,
            "textStyle": {
    
    
                "color": "#fff"
            }
        },
        "splitLine": {
    
     // 坐标轴在 grid 区域中的分隔线。默认数值轴(横向)显示,类目轴(纵向)不显示。
            "show": true,
            "lineStyle": {
    
     // 分隔线的样式设置。
                "color": [
                    "#ccc"
                ]
            }
        },
        "splitArea": {
    
     // 坐标轴在 grid 区域中的分隔区域,默认不显示。
            "show": false,
            "areaStyle": {
    
     // 分隔区域的样式设置。
                "color": [
                    "rgba(250,250,250,0.3)",
                    "rgba(200,200,200,0.3)"
                ]
            }
        }
    },
    // @数据滑竿
    "dataZoom": {
    
    
        "show": true,
        "backgroundColor": "rgba(47,69,84,0)",
        "dataBackgroundColor": "rgba(239,239,255,1)",
        "fillerColor": "rgba(182,162,222,0.2)",
        "handleColor": "#008acd",
        "handleSize": "100%",
        "textStyle": {
    
    
            "color": "#333333"
        }
    },

    "markPoint": {
    
    
        "label": {
    
    
            "color": "#eeeeee"
        },
        "emphasis": {
    
    
            "label": {
    
    
                "color": "#eeeeee"
            }
        }
    }
}

(4) 使用自定义loading
echarts不同版本的loading显示效果不太一样,echarts4的loading只有一种如下 详见文档
在这里插入图片描述
默认的loading default的正确打开方式应该是这样的:(这是官网api都没有的哦!)

var initChart = MyEcharts.initChart(option, "mixCharts");
/**
 * @param {string} “default” showLoading默认值
 * @param {Object} {
		text: 'loading', // loading显示的文字
        textColor: '#000', // 文字颜色
        fontSize: '12px', // 文字大小
        maskColor: 'rgba(255, 255, 255, 0.8)',
        showSpinner: true, // 是否显示gif动画,默认true
        color: '#c23531', // gif填充的颜色
        spinnerRadius: 10, 
        lineWidth: 5,
        zlevel: 0
	}
 */
initChart.showLoading(); 
//initChart.showLoading("default",{text:'暂无数据!',showSpinner: true}); // 或者指定配置

loading隐藏

initChart.hideLoading();
//initChart.hideLoading("default"); // 或者指定名称

敲黑板!重点来啦!如果以上的配置还不能满足需求呢?比如我想把转圈圈的动画换成自定义的图片
自定义loading详见echarts-util.js 文件loadingNodata方法
自定义的loading nodatas的正确打开方式应该是这样的:

initChart.showLoading("nodatas",{
    
    text:'暂无数据!',showSpinner: true});

loading隐藏

initChart.hideLoading("nodatas");
ps:我实在弄不下去了,有时间再进行补充吧!

3.代码实例

echartsUtil.html代码如下(示例):

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>echarts二次封装</title>
    <script src="./js/echarts.min.js"></script>
    <script src="./js/mysetTheme.js"></script>
    <script src="./js/echarts-util.js"></script>
    <style>
        body,
        html {
    
    
            width: 100%;
            height: 100%;
            padding: 0;
            margin: 0;
            background: url("./image/bi_board_background.jpg") center center no-repeat;
            background-size: 100% 100%;
            background-color: rgb(31, 37, 49);
        }

        .container {
    
    
            display: grid;
            grid-gap: 10px;
            grid-template-columns: repeat(auto-fill, minmax(450px, 1fr));
            grid-auto-rows: 450px;
        }

        .container>div {
    
    
            border: 1px solid #0a6ebd;
            position: relative;
        }
    </style>
</head>

<body>
    <div class="container">
        <div id="main">饼状图</div>
        <div id="pieC">环形饼图</div>
        <div id="mainLine">折线图</div>
        <div id="mainBar">柱状图</div>
        <div id="barGroup">柱状分组</div>
        <div id="mixCharts">混搭</div>
        <div id="acrossBar">横向柱状图</div>
        <div id="Radar">雷达图</div>
        <div id="Funnel">漏斗图</div>

    </div>
    <script>
        /**
         * 饼图 
        **/
        var data = [{
    
     name: '男生', value: 10 },
        {
    
     name: '女生', value: 20 }];
        var option = MyEcharts.EchartsOption.pie("男女人数统计", "单位(人)", data);
        var initChart = MyEcharts.initChart(option, "main");
        //要替换默认样式就取消下面注释
        // var options = {
    
    
        //     color: ["#FDB157", "#3498DB"],
        //     legend: {
    
    
        //         orient: 'vertical', //垂直:vertical; 水平 horizontal
        //         right: 'right',
        //     },
        //     series: [{
    
    
        //         radius: '55%', //圆的大小
        //         center: ['50%', '60%'],//位置居中
        //     }]
        // };
        // initChart.setOption(options);

        /**
         * 环形饼图 滑翔
        **/
        var pieCData = [
            {
    
     value: 335, name: '直接访问' },
            {
    
     value: 310, name: '邮件营销' },
            {
    
     value: 234, name: '联盟广告' },
            {
    
     value: 135, name: '视频广告' },
            {
    
     value: 1548, name: '搜索引擎' }
        ]
        var option = MyEcharts.EchartsOption.pie("环形饼图", "种类数(份)", pieCData, ['40%', '60%']);
        var initChart = MyEcharts.initChart(option, "pieC");

        /**
         * 折线图 
        **/
        var nameLine = [];
        for (var i = 1; i <= 11; i++) {
    
    
            nameLine.push('11月' + i + '日');
        }
        var valLine = [0, -120, 1245, 0, -190, 1376, 1511, 1689, 1256, 1495, 1192];

        var dataLine = []
        for (var i = 0; i < nameLine.length; i++) {
    
    
            dataLine.push({
    
     name: nameLine[i], value: valLine[i], group: '出生人数1' })
            // dataLine.push({ name: nameLine[i], value: valLine.reverse()[i], group: '出生人数2' })
        }

        var option = MyEcharts.EchartsOption.Line("折线图", "单位(人)", dataLine);
        //区域填充样式(渐变)
        /*option.series[0].areaStyle = {
            color: {
                type: 'linear', // 线性渐变:linear,径向渐变:radial
                x: 0,
                y: 0,
                x2: 0,
                y2: 1,
                colorStops: [{
                    offset: 0.2, color: '#838CFF' // 0% 处的颜色
                }, {
                    offset: 0.6, color: 'transparent' // 100% 处的颜色
                }],
                global: false // 缺省为 false
            }
            // 纹理填充
            // color: {
            //     image: imageDom, // 支持为 HTMLImageElement, HTMLCanvasElement,不支持路径字符串
            //     repeat: 'repeat' // 是否平铺,可以是 'repeat-x', 'repeat-y', 'no-repeat'
            // }
        }*/

        var initChartLine = MyEcharts.initChart(option, "mainLine");

        /**
         * 柱状图 
        **/
        var option = MyEcharts.EchartsOption.bar("柱状图", "单位(人)", dataLine);
        //柱子线性渐变
        option.series[0].itemStyle = {
    
    
            color: new echarts.graphic.LinearGradient(
                0, 0, 0, 1, //x0, y0, x2, y2, 范围从 0 - 1,相当于在图形包围盒中的百分比。x0 x2从左到右横向的渐变方向,y0 y2从上到下纵向的渐变方向
                [
                    {
    
     offset: 0, color: '#F97332' },
                    {
    
     offset: 0.5, color: '#F97332' },
                    {
    
     offset: 1, color: 'transparent' }
                ]
            )
        }
        var initChart = MyEcharts.initChart(option, "mainBar");

        /**
         * 柱状分組 
        **/
        var nameBar = [];
        for (var j = 1; j <= 6; j++) {
    
    
            nameBar.push('11月' + j + '日');
        }
        var value = [55, 900, 1245, 1530, 1376, 1376];

        var dataBar = []
        for (var i = 0; i < nameBar.length; i++) {
    
    
            dataBar.push({
    
     name: nameBar[i], value: value[i], group: '人生1' })
        }
        var dataBar2 = [];
        for (var i = 0; i < nameBar.length; i++) {
    
    
            dataBar2.push({
    
     name: nameBar[i], value: value.reverse()[i], group: '人生2' })
        }
        var option = MyEcharts.EchartsOption.bar("柱状分组", "种类数(份)", [...dataBar, ...dataBar2]);
        // console.log([...dataBar, ...dataBar2]);
        var initChart = MyEcharts.initChart(option, "barGroup");

        /**
         * 横向柱状图 
        **/
        var dataacrossBar = [];
        var valBar = [55, 900, 1245, 1530, 0, 1376, 1511, 1689, 1856, 1495, 1292];
        for (var i = 0; i < nameBar.length; i++) {
    
    
            dataacrossBar.push({
    
     name: nameBar[i], value: valBar[i], group: '很想' })
        }
        var option = MyEcharts.EchartsOption.acrossBar("横向柱状图", "种类数(份)", dataacrossBar);
        /**
         * 未分组的情况下(group)使每个柱子独立的颜色
        **/
        option.series[0].itemStyle = {
    
    
            normal: {
    
    
                color: function (params) {
    
    
                    let color = myTheme.color;
                    return color[params.dataIndex]
                },
            }
        }
        var initChart = MyEcharts.initChart(option, "acrossBar");


        /**
         * 双y轴,和柱状折线混搭
        **/
        var nameBar = [];
        for (var j = 1; j <= 6; j++) {
    
    
            nameBar.push('11月' + j + '日');
        }
        var value = [55, 90, 124, 153, 137, 105];

        var dataBar = []
        for (var i = 0; i < nameBar.length; i++) {
    
    
            dataBar.push({
    
     name: nameBar[i], value: value[i], group: '人生1' })
        }

        var value2 = [12.0, 23.2, 25.6, 62.2, 32.6, 43.3];
        var dataBar2 = [];
        for (var i = 0; i < nameBar.length; i++) {
    
    
            dataBar2.push({
    
     name: nameBar[i], value: value2.reverse()[i], group: '人生2', yAxisIndex: 1 })
        }
        var dataBar3 = [];
        for (var i = 0; i < nameBar.length; i++) {
    
    
            dataBar2.push({
    
     name: nameBar[i], value: value2[i], group: '人生3', yAxisIndex: 1 })
        }
        // console.log( [...dataBar, ...dataBar2, ...dataBar3]);
        // var option = MyEcharts.EchartsOption.doubleYMixUp("混搭/双y轴", "种类数(份)", [...dataBar, ...dataBar2, ...dataBar3], 'bar');
        var option = MyEcharts.EchartsOption.doubleYMixUp("混搭/双y轴", "种类数(份)", [...dataBar, ...dataBar2, ...dataBar3], ['line', 'bar', 'line']);
        //重置右侧y轴样式
        /*问题1:重置yAxis的样式后,点击图例无法控制y轴显隐*/
        option.yAxis[1] = {
    
    
            type: 'value',
            name: '温度',
            interval: 5,
            splitLine: {
    
    
                show: false, 去除网格线
            },
            axisLabel: {
    
    
                formatter: '{value} °C'
            }
        }
        option.yAxis[0].name = '%';
        option.series[0].label = {
    
    
            show: true,
            position: 'top',
            color: '#FFFFFF',
            formatter: '{c}%'
        };
        var initChart = MyEcharts.initChart(option, "mixCharts");

        var options = {
    
    
            yAxis: [{
    
    
                name: '%',
            }, {
    
    
                type: 'value',
                name: '温度',
                interval: 5,
                splitLine: {
    
    
                    show: false, // 去除网格线
                },
                axisLabel: {
    
    
                    formatter: '{value}'
                }
            }],
            series: [
                {
    
    
                    label: {
    
    
                        show: true,
                        position: 'top',
                        color: '#FFFFFF',
                        formatter: '{c}%'
                    }
                }
            ]

        }
        initChart.setOption(options);
        //添加自定义loading
        // initChart.showLoading("nodatas",{text:'暂无数据!',showSpinner: true});
        // initChart.hideLoading("nodatas");

        /**
         * 雷达图Radar
        **/

        var option = MyEcharts.EchartsOption.Radar("雷达图", "", [...dataBar, ...dataBar2, ...dataBar3]);
        var initChart = MyEcharts.initChart(option, "Radar");

        /**
         * 漏斗图Funnel
        **/
        var option = MyEcharts.EchartsOption.Funnel("漏斗图Funnel", "", [...dataBar, ...dataBar2, ...dataBar3]);
        var initChart = MyEcharts.initChart(option, "Funnel");
    </script>
</body>

</html>

echarts-util.js代码如下(示例):

/**
 * 封装echarts 工具
 * Author: abner
 * Date: 2021-1-5 更新
 */
let MyEcharts = {
    
    
    echartSet: [], // 表格集合
    //整理数据没有分组类型的,适合饼图
    EchartsDataFormate: {
    
    
        NoGroupFormate: function (data) {
    
    
            //category 的数据存储
            let categorys = [];
            //data 的数据存储
            let datas = [];
            //遍历
            for (let i = 0; i < data.length; i++) {
    
    
                categorys.push(data[i].name || "");
                //定义一个中间变量
                let temp_data = {
    
     value: data[i].value || 0, name: data[i].name || "" };
                datas.push(temp_data);
            }
            return {
    
     categorys: categorys, data: datas };
        },
        //整理数据有分组类型的,适合折线图、柱形图(分组,堆积)
        //数据格式:{group:XXX,name:XXX,value:XXX} 注意:group不填写没有图例,也无法(分组,堆积)
        /**
         * @param data : json数据<br>
         * @param type Array | string: 图表类型<br>
         * let data1 = [ <br>
         *      { group:'类型1' , name: '1月', value: 10 }, <br>
         *    { group:'类型2' , name: '1月', value: 15 }, <br>
         *    { group:'类型1' , name: '2月', value: 25 }, <br>
         *    { group:'类型2' , name: '2月', value: 12 }, <br>
         *    { group:'类型1' , name: '3月', value: 22 }, <br>
         *    { group:'类型2' , name: '3月', value: 12 }, <br>
         *    ];
         *
         */
        GroupFormate: function (data, type) {
    
    
            //用于存储类型名称(图例名)
            let groups = [];
            //用于存储xAxis.data数据(x轴名称)
            let names = [];
            //存储返回series数据 (一个或者多个)
            let series = [];
            let yAxisIndex = 0;

            for (let i = 0; i < data.length; i++) {
    
    
                //判断data[i].group是否存在数租groups中
                if (!groups.contains(data[i].group)) {
    
    
                    //不存在则跳进 存放
                    groups.push(data[i].group);
                }
                //判断name数据是否存在 数组names中
                if (!names.contains(data[i].name)) {
    
    
                    //不存在则跳进 存放
                    names.push(data[i].name);
                }
            }

            //遍历分类
            for (let i = 0; i < groups.length; i++) {
    
    
                //定义一个series中间变量
                let temp_series = {
    
    };
                //定义data.value数据存储
                let temp_data = [];
                //定义图形类型
                let temp_type = type.constructor === Array ? type[i] : type;
                //遍历所有数据
                for (let j = 0; j < data.length; j++) {
    
    
                    //遍历data.name数据
                    for (let k = 0; k < names.length; k++) {
    
    
                        //判断所有分类中的所有数据含name数据分开
                        if (groups[i] == data[j].group && names[k] == data[j].name) {
    
    
                            temp_data.push(data[j].value);
                            //判断y轴对应的数据,如果存在yAxisIndex则使用此数据,否则使用默认值  默认:0
                            yAxisIndex = data[j].yAxisIndex ? data[j].yAxisIndex : 0;
                        }
                    }
                }

                temp_series = {
    
    
                    name: groups[i],
                    type: temp_type === 'acrossBar' ? 'bar' : temp_type, //横向柱状图:acrossBar
                    data: temp_data,
                    yAxisIndex: yAxisIndex
                };

                //每个柱子或拐点对应的文字位置和颜色。echarts3是在label.normal里配置,echart4中兼容
                temp_series.label = {
    
    
                    position: 'top',
                    show: true,
                    textStyle: {
    
    
                        color: '#fff' //auto则根据系列色同步
                    },
                    formatter: function (params) {
    
     //当值为0时不显示在柱子或拐点顶部   
                        let val = params.value;
                        return val === 0 ? '' : val;
                    }
                };

                // 柱状图参数配置
                if (temp_type === 'bar') {
    
    
                    temp_series.barMaxWidth = 24; //柱宽
                }
                // 折线图参数配置
                if (temp_type === 'line') {
    
    
                    temp_series.lineStyle = {
    
     width: 4 }; //线租
                    temp_series.smooth = true; //拐点平滑
                }
                // 横向柱状图参数配置
                if (temp_type === 'acrossBar') {
    
    
                    temp_series.barMaxWidth = 24; //柱宽
                    temp_series.label = {
    
    
                        position: 'right',
                        show: true,
                        textStyle: {
    
    
                            color: 'auto' //auto则根据系列色同步
                        }
                    };

                }
                series.push(temp_series);
            }
            // console.log(groups)
            // console.log(names)
            // console.log(series)
            return {
    
     groups: groups, category: names, series: series };
        },
        /**
         * 雷达图数据格式化
         */
        RadarFormate: function (data, type) {
    
    
            //用于存储类型名称
            let groups = [];
            //用于存储data.name数据
            let names = [];
            //存储最大值数组
            let indicators = [];
            //定义data.value数据存储
            let temp_data = [];
            for (let i = 0; i < data.length; i++) {
    
    
                //判断data[i].group是否存在数租groups中
                if (!groups.contains(data[i].group)) {
    
    
                    //不存在则跳进 存放
                    groups.push(data[i].group);
                }

                //判断name数据是否存在 数组names中
                if (!names.contains(data[i].name)) {
    
    
                    //不存在则跳进 存放
                    names.push(data[i].name);
                }
            }
            for (let i = 0; i < names.length; i++) {
    
    
                //中
                let temp_maxValue = [];
                for (let j = 0; j < data.length; j++) {
    
    
                    if (names[i] == data[j].name) {
    
    
                        temp_maxValue.push(data[j].value);
                    }
                }
                indicators.push({
    
     name: names[i], max: Number(temp_maxValue.max() * 2 / 1.5).toFixed(2) })
            }
            //遍历分类
            for (let i = 0; i < groups.length; i++) {
    
    
                //定义一个series中间变量
                let temp_series = {
    
    };
                //定义datavalue数组
                let dataValues = [];
                //遍历所有数据
                for (let j = 0; j < data.length; j++) {
    
    
                    if (groups[i] == data[j].group) {
    
    
                        dataValues.push(data[j].value);
                    }
                }
                temp_data.push({
    
     value: dataValues, name: groups[i] });
            }
            let series = {
    
     type: type, data: temp_data };
            return {
    
     indicators: indicators, groups: groups, category: names, series: series };
        },
        /**
         * 漏斗图数据格式化
         */
        FunnelFormate: function (data, type) {
    
    
            //用于存储类型名称
            let groups = [];
            //用于存储data.name数据
            let names = [];
            //定义一个存放series的数组
            let series = [];
            for (let i = 0; i < data.length; i++) {
    
    
                //判断data[i].group是否存在数租groups中
                if (!groups.contains(data[i].group)) {
    
    
                    //不存在则跳进 存放
                    groups.push(data[i].group);
                }

                //判断name数据是否存在 数组names中
                if (!names.contains(data[i].name)) {
    
    
                    //不存在则跳进 存放
                    names.push(data[i].name);
                }
            }
            let width = parseInt(100 / groups.length);
            //遍历分类
            for (let i = 0; i < groups.length; i++) {
    
    
                //定义data.value数据存储
                let temp_data = [];
                let k = 0;
                //遍历所有数据
                for (let j = 0; j < data.length; j++) {
    
    
                    //判断所有分类中的所有数据含name数据分开
                    if (groups[i] == data[j].group) {
    
    
                        k++;
                        temp_data.push({
    
     value: k, name: data[j].name + ":" + data[j].value });
                    }
                }
                let left = width * i;
                series.push({
    
    
                    name: groups[i],
                    type: type,
                    sort: 'ascending',
                    grap: 2,
                    left: left + "%",
                    width: width - 5 + "%",
                    label: {
    
    
                        normal: {
    
    
                            show: true,
                            position: 'inside'
                        },
                        emphasis: {
    
    
                            textStyle: {
    
    
                                fontSize: 20
                            }
                        }
                    },
                    data: temp_data
                });
            }
            return {
    
     groups: groups, category: names, series: series };
        },
        /**
         * 仪表盘图数据格式化
         */
        GaugeFormate: function (data, type) {
    
    
            let temp_datas = [{
    
     value: data.value, name: data.name }];
            let names = data.name;
            //判断最大值和最小值几位数
            maxNum = Number(parseInt(data.value)).toString().length;
            minNum = Number(parseInt(data.value)).toString().length;
            if (minNum <= 2) {
    
    
                min = 0;
            } else {
    
    
                //最小值
                min = Math.pow(10, (maxNum - 1));
            }
            //最大值
            max = Math.pow(10, maxNum);
            let series = [];
            series.push({
    
    
                name: data.group,
                type: type,
                min: min,
                max: max,
                radius: '70%',
                startAngle: 180,
                endAngle: -0,
                axisLine: {
    
                // 坐标轴线
                    lineStyle: {
    
           // 属性lineStyle控制线条样式
                        color: [[0.09, 'lime'], [0.82, '#1e90ff'], [1, '#ff4500']],
                        width: 3,
                        shadowColor: '#fff', //默认透明
                        shadowBlur: 10
                    }
                },
                axisLabel: {
    
                // 坐标轴小标记
                    textStyle: {
    
           // 属性lineStyle控制线条样式
                        fontWeight: 'bolder',
                        color: '#444',
                        shadowColor: '#fff', //默认透明
                        shadowBlur: 10
                    }
                },
                axisTick: {
    
                // 坐标轴小标记
                    length: 15,        // 属性length控制线长
                    lineStyle: {
    
           // 属性lineStyle控制线条样式
                        color: 'auto',
                        shadowColor: '#fff', //默认透明
                        shadowBlur: 10
                    }
                },
                splitLine: {
    
               // 分隔线
                    length: 25,         // 属性length控制线长
                    lineStyle: {
    
           // 属性lineStyle(详见lineStyle)控制线条样式
                        width: 3,
                        color: 'auto',
                        shadowColor: '#fff', //默认透明
                        shadowBlur: 10
                    }
                },
                pointer: {
    
               // 分隔线
                    shadowColor: '#fff', //默认透明
                    shadowBlur: 5
                },
                title: {
    
    
                    offsetCenter: ['-10%', '30%'],
                    textStyle: {
    
           // 其余属性默认使用全局文本样式,详见TEXTSTYLE
                        fontWeight: 'bolder',
                        fontSize: 14,
                        fontStyle: 'italic',
                        color: '#',
                        shadowColor: '#fff', //默认透明
                        shadowBlur: 10
                    }
                },
                detail: {
    
    
                    backgroundColor: 'rgba(30,144,255,0.8)',
                    borderWidth: 1,
                    borderColor: '#fff',
                    shadowColor: '#fff', //默认透明
                    shadowBlur: 5,
                    fontSize: 14,
                    offsetCenter: ['20%', '30%'],       // x, y,单位px
                    textStyle: {
    
           // 其余属性默认使用全局文本样式,详见TEXTSTYLE
                        fontWeight: 'bolder',
                        color: '#fff'
                    }
                },
                data: temp_datas
            });
            return {
    
     category: names, series: series };
        }

    },

    //生成图形option
    EchartsOption: {
    
    
        /**
         * 饼图
         * @param title : 标题<br>
         * @param subtext :副标题<br>
         * @param data : json 数据
         * @param radiusArr : array [内环百分比,外环百分比],不指定为普通饼图
         *
         */
        pie: function (title, subtext, data, radiusArr) {
    
    
            //数据格式
            let datas = MyEcharts.EchartsDataFormate.NoGroupFormate(data);
            let option = {
    
    
                //标题
                title: {
    
    
                    text: title || "",	//标题
                    subtext: subtext || "", //副标题
                },
                //提示
                tooltip: {
    
    
                    show: true,
                    trigger: 'item',
                    formatter: "{a} <br/>{b} : {c} ({d}%)"
                },
                //组建
                legend: {
    
    
                    data: datas.categorys
                },
                series: [
                    {
    
    
                        name: title || "",
                        type: 'pie',	//类型
                        radius: radiusArr || '48%', //圆的大小
                        center: ['50%', '50%'],//位置居中
                        data: datas.data,
                        emphasis: {
    
     //高亮的扇区和标签样式。
                            shadowBlur: 10,
                            shadowOffsetX: 0,
                            shadowColor: 'rgba(0, 0, 0, 0.5)'
                        },
                        labelLine: {
    
     //引导线
                            show: false,
                        },
                        label: {
    
    
                            textStyle: {
    
    
                                color: 'auto'  //改变标示文字的颜色
                            }
                        }
                    }
                ]
            };
            return option;
        },
        /**
         * 柱形图
         * @param title : 标题<br>
         * @param subtext :副标题<br>
         * @param data : json 数据
         */
        bar: function (title, subtext, data) {
    
    
            let datas = MyEcharts.EchartsDataFormate.GroupFormate(data, 'bar');
            let option = {
    
    
                //标题
                title: {
    
    
                    text: title || "",	//标题
                    subtext: subtext || "", //副标题
                },
                //提示
                tooltip: {
    
    
                    show: true,
                    trigger: 'axis', //散点图,饼图等无类目轴的图表中使用:'item';
                    axisPointer: {
    
     //鼠标指向背景
                        type: 'shadow', //'line' 直线指示器 ,'shadow' 阴影指示器 ,'none' 无指示器 ,'cross' 十字准星指示器。其实是种简写,表示启用两个正交的轴的 axisPointer。
                        label: {
    
    
                            show: true
                        }
                    },

                    // formatter: function (params) {
    
    
                    //     return MyEcharts.resetTooltip(params);
                    // }
                },
                // 工具条
                toolbox: {
    
    
                    show: false, // 默认显示
                    feature: {
    
    
                        dataZoom: {
    
    
                            yAxisIndex: 'none'
                        },
                        dataView: {
    
     readOnly: false },
                        magicType: {
    
     type: ['line', 'bar'] },
                        restore: {
    
    },
                        saveAsImage: {
    
    }
                    }
                },
                // 数据滑竿
                dataZoom: [
                    {
    
    
                        show: false,
                        realtime: true,
                    },
                    {
    
    
                        type: 'slider',
                        realtime: true,
                    }
                ],
                //组建
                legend: {
    
    
                    data: datas.groups.map((text) => {
    
    
                        return {
    
     name: text, icon: 'rect' } //icon图形样式:'circle', 'rect', 'roundRect', 'triangle', 'diamond', 'pin', 'arrow'
                    })
                },
                //水平坐标
                xAxis: [
                    {
    
    
                        name: '', //x轴单位
                        nameTextStyle: {
    
    //x轴上方单位的颜色
                            color: 'auto'
                        },
                        type: 'category',
                        data: datas.category
                    }
                ],
                //垂直坐标
                yAxis: [
                    {
    
    
                        name: '', //y轴单位
                        nameTextStyle: {
    
    //y轴上方单位的颜色
                            color: '#151515'
                        },
                        type: 'value'
                    }
                ],
                //series数据
                series: datas.series
            };
            return option;
        },
        /**
         * 横向柱形图
         * @param title : 标题<br>
         * @param subtext :副标题<br>
         * @param data : json 数据
         */
        acrossBar: function (title, subtext, data) {
    
    
            let datas = MyEcharts.EchartsDataFormate.GroupFormate(data, 'acrossBar');
            let option = {
    
    
                //标题
                title: {
    
    
                    text: title || "",	//标题
                    subtext: subtext || "", //副标题
                },
                //提示
                tooltip: {
    
    
                    show: true,
                    trigger: 'axis', //散点图,饼图等无类目轴的图表中使用:'item';
                    axisPointer: {
    
     //鼠标指向背景
                        type: 'none', //'line' 直线指示器 ,'shadow' 阴影指示器 ,'none' 无指示器 ,'cross' 十字准星指示器。其实是种简写,表示启用两个正交的轴的 axisPointer。
                        label: {
    
    
                            show: true
                        }
                    },
                    formatter: function (params) {
    
    
                        return MyEcharts.resetTooltip(params);
                    }
                },
                //组建
                legend: {
    
    
                    data: datas.groups.map((text) => {
    
    
                        return {
    
     name: text, icon: 'rect' } //icon图形样式:'circle', 'rect', 'roundRect', 'triangle', 'diamond', 'pin', 'arrow'
                    })
                },
                //水平坐标
                xAxis: [
                    {
    
    
                        name: '', //x轴单位
                        nameTextStyle: {
    
    //x轴上方单位的颜色
                            color: '#151515'
                        },
                        type: 'value'
                    }
                ],
                //垂直坐标
                yAxis: [
                    {
    
    
                        name: '', //y轴单位
                        nameTextStyle: {
    
    //y轴上方单位的颜色
                            color: '#151515'
                        },
                        type: 'category',
                        data: datas.category
                    }
                ],
                //series数据
                series: datas.series
            };
            return option;
        },
        /**
          * 双y轴/混搭
          * @param title : string 标题
          * @param subtext : string 副标题
          * @param data : json 数据
          * @param type : Array 或 string,数组时需要和图例个数相对应,字符串时为统一类型 **注意:type不管为哪种类型时都需要在数据中指定yAxisIndex的值**
          */
        doubleYMixUp: function (title, subtext, data, type) {
    
    
            let datas = MyEcharts.EchartsDataFormate.GroupFormate(data, type);
            let option = {
    
    
                //标题
                title: {
    
    
                    text: title || "",	//标题
                    subtext: subtext || "", //副标题
                },
                //提示
                tooltip: {
    
    
                    show: true,
                    trigger: 'axis', //散点图,饼图等无类目轴的图表中使用:'item';
                    axisPointer: {
    
     //鼠标指向背景
                        type: 'shadow', //'line' 直线指示器 ,'shadow' 阴影指示器 ,'none' 无指示器 ,'cross' 十字准星指示器。其实是种简写,表示启用两个正交的轴的 axisPointer。
                        label: {
    
    
                            show: true
                        }
                    }
                },
                //组建
                legend: {
    
    
                    data: datas.groups.map((text) => {
    
    
                        return {
    
     name: text, icon: 'rect' } //icon图形样式:'circle', 'rect', 'roundRect', 'triangle', 'diamond', 'pin', 'arrow'
                    })
                },
                //水平坐标
                xAxis: [
                    {
    
    
                        name: '', //x轴单位
                        type: 'category',
                        data: datas.category,
                    }
                ],
                //垂直坐标
                yAxis: [
                    {
    
    
                        name: '', //y轴单位
                        type: 'value',
                        splitLine: {
    
    
                            show: false, 去除网格线
                        }
                    },
                    {
    
    
                        name: '', //右y轴单位
                        type: 'value',
                        splitLine: {
    
    
                            show: false, 去除网格线
                        }
                    }
                ],
                //series数据
                series: datas.series
            };
            return option;
        },
        /**
         * 折线图
         * @param title : 标题<br>
         * @param subtext :副标题<br>
         * @param data : json 数据
         */
        Line: function (title, subtext, data) {
    
    
            let datas = MyEcharts.EchartsDataFormate.GroupFormate(data, 'line');
            let option = {
    
    
                //标题
                title: {
    
    
                    text: title || "",	//标题
                    subtext: subtext || "", //副标题
                },
                //提示
                tooltip: {
    
    
                    show: true,
                    trigger: 'axis',
                    // formatter: function (params) {
    
    
                    //     debugger
                    //     return MyEcharts.resetTooltip(params);
                    // }
                },
                //组建
                legend: {
    
    
                    data: datas.groups.map((text) => {
    
    
                        return {
    
     name: text, icon: 'rect' } //icon图形样式:'circle', 'rect', 'roundRect', 'triangle', 'diamond', 'pin', 'arrow'
                    })
                },
                //水平坐标
                xAxis: [
                    {
    
    
                        type: 'category',
                        boundaryGap: false,
                        splitLine: {
    
    
                            show: false, 去除网格线
                        },
                        data: datas.category,
                    }
                ],
                //垂直坐标
                yAxis: [
                    {
    
    
                        type: 'value'
                    }
                ],
                //series数据
                series: datas.series
            };
            return option;
        },
        /**
         * 雷达图
         * @param title : 标题<br>
         * @param subtext :副标题<br>
         * @param data : json 数据
         */
        Radar: function (title, subtext, data) {
    
    
            let datas = MyEcharts.EchartsDataFormate.RadarFormate(data, 'radar');
            let option = {
    
    
                //标题
                title: {
    
    
                    text: title || "",	//标题
                    subtext: subtext || "", //副标题
                },
                //提示
                tooltip: {
    
    
                    show: true,
                },
                //组建
                legend: {
    
    
                    data: datas.groups
                },
                radar: {
    
    
                    name: {
    
    
                        textStyle: {
    
    
                            color: '#fff',
                            backgroundColor: '#999',
                            borderRadius: 3,
                            padding: [3, 5]
                        }
                    },
                    indicator: datas.indicators
                },
                series: datas.series
            };
            return option;
        },
        /**
         * 漏斗图
         * @param title : 标题<br>
         * @param subtext :副标题<br>
         * @param data : json 数据
         */
        Funnel: function (title, subtext, data) {
    
    
            let datas = MyEcharts.EchartsDataFormate.FunnelFormate(data, 'funnel');
            let option = {
    
    
                //标题
                title: {
    
    
                    text: title || "",	//标题
                    subtext: subtext || "", //副标题
                },
                //提示
                tooltip: {
    
    
                    show: true,
                    trigger: 'item',
                    formatter: "{a} <br/>{b} ({c}%)"
                },
                //组建
                legend: {
    
    
                    data: datas.groups,
                },
                series: datas.series
            };
            return option;
        },
        /**
         * 仪表图
         * @param title : 标题<br>
         * @param subtext :副标题<br>
         * @param data : json 数据
         */
        Gauge: function (title, subtext, data) {
    
    
            let datas = MyEcharts.EchartsDataFormate.GaugeFormate(data, 'gauge');
            let option = {
    
    
                //标题
                title: {
    
    
                    text: title || "",	//标题
                    subtext: subtext || "", //副标题
                },
                //提示
                tooltip: {
    
    
                    show: true,
                    formatter: "{a} <br/>{b}:{c}"
                },

                series: datas.series
            };
            return option;
        }
    },
    /**
     * 重置Tooltip样式
     * @param params : object tooltip函数返回值
     */
    resetTooltip: function (params) {
    
    
        if (params.length === 1) {
    
     //只有一组数据时
            let text = params[0].seriesName + '<br/>';
            let colorStops = params[0].color;
            if (typeof colorStops === 'object') {
    
     //色彩为渐变时
                colorStops = params[0].color.colorStops[0].color; //***待优化,此处color不一定有颜色,第一个可能为透明色                          
            }
            text += '<span style="display:inline-block;margin-right:5px;border-radius:50%;width:10px;height:10px;left:5px;background-color:' + colorStops + '"></span>' + params[0].axisValue + ' : ' + params[0].value + '<br/>';
            return text;
        } else {
    
     //一组 多条数据时
            let text = params[0].axisValue + '<br/>';
            params.forEach((item) => {
    
    
                let colorStops = item.color;
                if (typeof colorStops === 'object') {
    
     //色彩为渐变时
                    colorStops = item.color.colorStops[0].color; //***待优化,此处color不一定有颜色,第一个可能为透明色                          
                }
                text += '<span style="display:inline-block;margin-right:5px;border-radius:50%;width:10px;height:10px;left:5px;background-color:' + colorStops + '"></span>' + item.seriesName + ' : ' + item.value + '<br/>';
            })
            return text;
        }
    },
    /**
     * @param option : option
     * @param echartId : 图表的id 需要加引号
     */
    initChart: function (option, echartId) {
    
    
        let container = eval("document.getElementById('" + echartId + "')");
        let myChart = echarts.init(container, myTheme);
        console.log(myChart.getOption());
        myChart.setOption(option, true);	// (1图表数据: Object, 2是否不跟之前设置的option进行合并?默认为false,即合并: boolean, 3在设置完option后是否不立即更新图表?默认为false,即立即更新。: boolean)
        this.echartSet.push(myChart); // 存储已初始化的图表实例
        this.resize(); // 添加图表大小改变事件
        return myChart;
    },
    //图表大小改变事件监听
    resize: function () {
    
    
        try {
    
    
            window.onresize = function () {
    
    
                isDebounce(function () {
    
    
                    MyEcharts.echartSet.forEach(item => {
    
    
                        item.resize();
                    })
                }, 300);
            }.bind(this);
        } catch (error) {
    
     }
    }
};


/**
 * 数组是否存在某数据
 * @param obj
 * @returns {Boolean}
 */
Array.prototype.contains = function (obj) {
    
    
    let i = this.length;
    while (i--) {
    
    
        if (this[i] === obj) {
    
    
            return true;
        }
    }
    return false;
};
/**
 * 数组中最大值 最小值
 * @param array
 * @returns
 */
Array.prototype.max = function () {
    
    
    return Math.max.apply({
    
    }, this);
};
Array.prototype.min = function () {
    
    
    return Math.min.apply({
    
    }, this);
};


/**
 * 判断是否为整数
 * @param obj
 * @returns {Boolean}
 */
function isInteger(obj) {
    
    
    return obj % 1 === 0;
}
/**
 * 判断值是否包含指定字符
 * @param str
 * @returns {Boolean}
 */
function myRegExp(str) {
    
    
    let patt = new RegExp(/[%|$]/)
    return patt.test(str);
}

/**防抖函数
 * 当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。
 * 适用于延迟时间后触发一次事件。
 *使用方式:isDebounce(函数名,延迟时间)();
 */
let isTimer; // 维护一个 timer
function isDebounce(fn, delay) {
    
    
    try {
    
    
        let _this = this; // 取debounce执行作用域的this
        let args = arguments;
        if (isTimer) {
    
    
            clearTimeout(isTimer);
        }
        isTimer = setTimeout(function () {
    
    
            fn.apply(_this, args); // 用apply指向调用debounce的对象,相当于_this.fn(args);
        }, delay);
    } catch (error) {
    
    
        console.log(error);
    }
};

/**自定义loading
 * 当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。
 * 适用于延迟时间后触发一次事件。
 *使用方式:isDebounce(函数名,延迟时间)();
 */

function loadingNodata(api, opts) {
    
    
    let PI = Math.PI;
    opts = opts || {
    
    };
    opts = new echarts.util.defaults(opts, {
    
    
        text: 'loading', // loading显示的文字
        textColor: '#000', // 文字颜色
        fontSize: '12px', // 文字大小
        maskColor: 'rgba(255, 255, 255, 0.8)',
        showSpinner: true, // 是否显示gif动画
        color: '#c23531', // gif填充的颜色
        spinnerRadius: 10,
        lineWidth: 5,
        zlevel: 0
    })



    var group = new echarts.graphic.Group();
    var mask = new echarts.graphic.Rect({
    
    
        style: {
    
    
            fill: opts.maskColor
        },
        zlevel: opts.zlevel,
        z: 10000
    });
    group.add(mask);
    var font = opts.fontSize + ' sans-serif';
    var labelRect = new echarts.graphic.Rect({
    
    
        style: {
    
    
            fill: 'none',
            text: opts.text,
            font: font,
            textPosition: 'right',
            textDistance: 10,
            textFill: opts.textColor
        },
        zlevel: opts.zlevel,
        z: 10001
    });
    group.add(labelRect);
    if (opts.showSpinner) {
    
    
        var arc = new echarts.graphic.Arc({
    
    
            shape: {
    
    
                startAngle: -PI / 2,
                endAngle: -PI / 2 + 0.1,
                r: opts.spinnerRadius
            },
            style: {
    
    
                stroke: opts.color,
                lineCap: 'round',
                lineWidth: opts.lineWidth
            },
            zlevel: opts.zlevel,
            z: 10001
        });
        arc.animateShape(true)
            .when(1000, {
    
    
                endAngle: PI * 3 / 2
            })
            .start('circularInOut');
        arc.animateShape(true)
            .when(1000, {
    
    
                startAngle: PI * 3 / 2
            })
            .delay(300)
            .start('circularInOut');
        group.add(arc);
    }

    //添加计算canvas文字宽度方法
    api.getTextWith = function (
        text = '',
        fontStyle = '14px/1.5715 "Source Sans Pro, Helvetica Neue, Helvetica, Arial, sans-serif"', // 设置字体大小和字体
    ) {
    
    
        const canvas = document.createElement('canvas');
        const context = canvas.getContext('2d');
        context.font = fontStyle;
        const elem = context.measureText(text);
        return elem.width;
    }

    group.resize = function () {
    
    
        var textWidth = api.getTextWith(opts.text, font);
        var r = opts.showSpinner ? opts.spinnerRadius : 0;
        console.log("@r" + r);
        console.log("@showSpinner" + opts.showSpinner);
        // cx = (containerWidth - arcDiameter - textDistance - textWidth) / 2
        // textDistance needs to be calculated when both animation and text exist
        var cx = (api.getWidth() - r * 2 - (opts.showSpinner && textWidth ? 10 : 0) - textWidth) / 2
        // only show the text
        // - (opts.showSpinner ? 0 : textWidth / 2);
        var cy = api.getHeight() / 2;
        opts.showSpinner && arc.setShape({
    
    
            cx: cx,
            cy: cy
        });
        labelRect.setShape({
    
    
            x: cx - r,
            y: cy - r,
            width: r * 2,
            height: r * 2
        });

        mask.setShape({
    
    
            x: 0,
            y: 0,
            width: api.getWidth(),
            height: api.getHeight()
        });
    };

    group.resize();
    return group;
};
//向全局echarts对象注册新的loading: nodatas
echarts.registerLoading("nodatas", loadingNodata);

4.效果展示

在这里插入图片描述

总结

可能有些地方还不算完善,大家有问题留言,我会及时更新!
都看到这里了,还不给个三连QAQ!

猜你喜欢

转载自blog.csdn.net/weixin_48463654/article/details/112293018