使用OOP思想二次封装echarts

最近公司写几个报表模块,抽出空余时间简单的封装了一下。对原始的echarts进行二次封装、更方便维护、创建、管理;

源码地址

效果

在这里插入图片描述

1.文件目录说明

|-- echarts-extends
    |-- inedx.html              #视图
    |-- charts-class.js         #各类图表class
    |-- chart-factory.js        #图表工厂
    |-- utils.js                #工具方法

2.使用

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Echarts</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.0.2/echarts.common.js"></script>
    <style>
        .my-card {
            display: block;
            width: 600px;
            border: 1px solid #ddd;
            margin: 20px auto;
            border-radius: 5px;
        }
        .my-card .card-header {
            height: 50px;
            line-height: 50px;
            padding: 0 20px;
            border-bottom: 1px solid #ddd;
            user-select: none;
        }
        
        .my-card .card-content {
            min-height: 300px;
            padding: 10px;
        }
    </style>
</head>
<body>
    <div class="my-card">
        <div class="card-header">图表1</div>
        <div class="card-content" id="chart1"></div>
    </div>
    <div class="my-card">
        <div class="card-header">图表2</div>
        <div class="card-content" id="chart2"></div>
    </div>

    <div class="my-card">
        <div class="card-header">图表3</div>
        <div class="card-content" id="chart3"></div>
    </div>

    <script src="./utils.js"></script>
    <script src="./charts-class.js"></script>
    <script src="./chart-factory.js"></script>
    <script>
        var chartFactory = null; //图表工厂
        function _init() {
            chartFactory = initChart();  //初始化图表
        }

        /**
         * 初始化图表
         * @return {Object} 图表工厂
         */
        function initChart() {
            var chartFactory = new ChartFactory();  //图表工厂
            chartFactory.batchCreate([
               	//多走势图
                {
                    type: 'MORE_TREND_LINE', //图表类型,(chart-class.js)中的枚举文件;
                    wrapId: '#chart1',  //图表挂载容器选择器
                    data: function (cb) { //data可以是你的默认数据,也可以走API去拿
                        var _self = this;
                        var  data = {
                            yUnit: "测试",
                            xAxis: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
                            legend: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎'],
                            series: [
                                {
                                    name: '邮件营销',
                                    type: 'line',
                                    stack: '总量',
                                    data: [120, 132, 101, 134, 90, 230, 210]
                                },
                                {
                                    name: '联盟广告',
                                    type: 'line',
                                    stack: '总量',
                                    data: [220, 182, 191, 234, 290, 330, 310]
                                },
                                {
                                    name: '视频广告',
                                    type: 'line',
                                    stack: '总量',
                                    data: [150, 232, 201, 154, 190, 330, 410]
                                },
                                {
                                    name: '直接访问',
                                    type: 'line',
                                    stack: '总量',
                                    data: [320, 332, 301, 334, 390, 330, 320]
                                },
                                {
                                    name: '搜索引擎',
                                    type: 'line',
                                    stack: '总量',
                                    data: [820, 932, 901, 934, 1290, 1330, 1320]
                                }
                            ]
                        };
                        
                        cb.call(_self, data) //调用cb函数,此时的cb === 每个图表的setData方法, 也可以使用 _self.setData(data);
                    }
                },
                {
                    type: 'RATIO',
                    wrapId: '#chart2',
                    data: function (cb) {
                        var _self = this;
                        var data =  [
                            {value: 1048, name: '搜索引擎'},
                            {value: 735, name: '直接访问'},
                            {value: 580, name: '邮件营销'},
                            {value: 484, name: '联盟广告'},
                            {value: 300, name: '视频广告'}
                        ]
                        cb.call(_self, data)
                    },

                    //事件,这里的事件可根据echarts提供的对应事件,key、value传递,底层代理绑定
                    events: {
                        click: function (param) {
                            console.log(param)
                        }
                    }
                },
                {
                    type: 'PILLARS',
                    wrapId: '#chart3',
                    data: function (cb) {
                        var _self = this;
                        var data = {
                            xAxis:['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
                            series: [120, 200, 150, 80, 70, 110, 130]
                        }
                        cb.call(_self, data)
                    }
                }
            ]); //批量创建图表
            chartFactory.getChartsData(); //获取图表数据
            return chartFactory;
        }

        _init();
    </script>
</body>
</html>

代码

index.html
<!--
 * @Author: your name
 * @Date: 2021-03-19 22:14:32
 * @LastEditTime: 2021-03-22 10:39:19
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: /Demo/finance-month.html
-->
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Echarts</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.0.2/echarts.common.js"></script>
    <style>
        .my-card {
            display: block;
            width: 600px;
            border: 1px solid #ddd;
            margin: 20px auto;
            border-radius: 5px;
        }
        .my-card .card-header {
            height: 50px;
            line-height: 50px;
            padding: 0 20px;
            border-bottom: 1px solid #ddd;
            user-select: none;
        }
        
        .my-card .card-content {
            min-height: 300px;
            padding: 10px;
        }
    </style>
</head>
<body>
    <div class="my-card">
        <div class="card-header">图表1</div>
        <div class="card-content" id="chart1"></div>
    </div>
    <div class="my-card">
        <div class="card-header">图表2</div>
        <div class="card-content" id="chart2"></div>
    </div>

    <div class="my-card">
        <div class="card-header">图表3</div>
        <div class="card-content" id="chart3"></div>
    </div>

    <script src="./utils.js"></script>
    <script src="./charts-class.js"></script>
    <script src="./chart-factory.js"></script>
    <script>
        var chartFactory = null; //图表工厂
        function _init() {
            chartFactory = initChart();  //初始化图表
        }

        /**
         * 初始化图表
         * @return {Object} 图表工厂
         */
        function initChart() {
            var chartFactory = new ChartFactory();  //图表工厂
            chartFactory.batchCreate([
                //产品销量类别走势
                {
                    type: 'MORE_TREND_LINE',
                    wrapId: '#chart1',
                    data: function (cb) {
                        var _self = this;
                        var  data = {
                            yUnit: "测试",
                            xAxis: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
                            legend: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎'],
                            series: [
                                {
                                    name: '邮件营销',
                                    type: 'line',
                                    stack: '总量',
                                    data: [120, 132, 101, 134, 90, 230, 210]
                                },
                                {
                                    name: '联盟广告',
                                    type: 'line',
                                    stack: '总量',
                                    data: [220, 182, 191, 234, 290, 330, 310]
                                },
                                {
                                    name: '视频广告',
                                    type: 'line',
                                    stack: '总量',
                                    data: [150, 232, 201, 154, 190, 330, 410]
                                },
                                {
                                    name: '直接访问',
                                    type: 'line',
                                    stack: '总量',
                                    data: [320, 332, 301, 334, 390, 330, 320]
                                },
                                {
                                    name: '搜索引擎',
                                    type: 'line',
                                    stack: '总量',
                                    data: [820, 932, 901, 934, 1290, 1330, 1320]
                                }
                            ]
                        };
                        cb.call(_self, data)
                    }
                },
                {
                    type: 'RATIO',
                    wrapId: '#chart2',
                    data: function (cb) {
                        var _self = this;
                        var data =  [
                            {value: 1048, name: '搜索引擎'},
                            {value: 735, name: '直接访问'},
                            {value: 580, name: '邮件营销'},
                            {value: 484, name: '联盟广告'},
                            {value: 300, name: '视频广告'}
                        ]
                        cb.call(_self, data)
                    },

                    //事件,这里的事件可根据echarts提供的对应事件,key、value传递,底层代理绑定
                    events: {
                        click: function (param) {
                            console.log(param)
                        }
                    }
                },
                {
                    type: 'PILLARS',
                    wrapId: '#chart3',
                    data: function (cb) {
                        var _self = this;
                        var data = {
                            xAxis:['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
                            series: [120, 200, 150, 80, 70, 110, 130]
                        }
                        cb.call(_self, data)
                    }
                }
            ]); //批量创建图表
            chartFactory.getChartsData(); //获取图表数据
            return chartFactory;
        }

        _init();
    </script>
</body>
</html>
chart-class.js
/*
 * @Description: 图表Class
 * @Author: Haor
 * @Date: 2021-03-19
 */

;(function (win, doc, echarts) {
    /**
     * 比例图表
     * @param {String} wrapperId 容器id
     * @param {Array} data 数据
     */
    function Ratio (wrapperId, data) {
        //配置文件
        this.option = {
            tooltip: {
                trigger: 'item',
                formatter: function (param) {
                    return (
                        param.marker +
                        ' ' +
                        param.name +
                        ':<strong>' +
                        param.value +
                        ' (' +
                        param.percent +
                        '%)</srtong>'
                    )
                },
            },
            legend: {
                orient: 'vertical',
                left: 'left',
            },
            series: [
                {
                    name: '',
                    type: 'pie',
                    radius: '50%',
                    data: [],
                    label: {
                        normal: {
                            show: true,
                            formatter: '{b}: {c}({d}%)',
                        },
                    },
                    emphasis: {
                        itemStyle: {
                            shadowBlur: 10,
                            shadowOffsetX: 0,
                            shadowColor: 'rgba(0, 0, 0, 0.5)',
                        },
                    },
                },
            ],
        }

        this.init(wrapperId, data);
    }

    /**
     * 设置图表数据
     * @param {Array} data
     */
    Ratio.prototype.setData = function (data) {
        this.option.series[0].data = Array.isArray(data) ? data : []
        this.chart.setOption(this.option)
    }

    /**
     * 多走势线
     * @param {String} wrapperId 容器id
     * @param {Array} data
     */
    function MoreTrendLine (wrapperId, data) {
        this.option = {
            tooltip: {
                trigger: 'axis',
            },
            legend: {
                data: [],
            },
            grid: {
                left: '3%',
                right: '4%',
                bottom: '3%',
                containLabel: true,
            },
            toolbox: {
                show: false,
            },
            xAxis: {
                type: 'category',
                boundaryGap: false,
                axisLabel: { interval: 0, rotate: 30 },
                data: [],
            },
            yAxis: {
                type: 'value',
                axisLabel: {
                    formatter: '{value}',
                },
            },
            series: [],
        }
        this.init(wrapperId, data);
    }

    /**
     * 设置图表数据
     * @param {Object} data
     * @param {String} data.yUnit y轴单位
     * @param {Array} data.series
     * @param {Array} data.xAxis
     * @param {Array} data.legend
     * 
     */
    MoreTrendLine.prototype.setData = function (data) {
        data = JSON.parse(JSON.stringify(data))
        this.option.yAxis.axisLabel.formatter = '{value}' + (data.yUnit || '')
        this.option.series = data.series
        this.option.xAxis.data = data.xAxis
        this.option.legend.data = data.legend
        this.option['_timer'] = Date.now()
        this.chart.setOption(this.option)
    }

    /**
     * 柱状图
     * @param {String} wrapperId 容器id
     * @param {Array} data
     */
    function Pillars (wrapperId, data) {
        this.option = {
            tooltip: {
                trigger: 'axis',
                axisPointer: {
                    type: 'cross',
                    crossStyle: {
                        color: '#999',
                    },
                },
            },
            legend: {
                data: [],
            },
            xAxis: [
                {
                    type: 'category',
                    data: [],
                    axisLabel: { interval: 0, rotate: 30 },
                    axisPointer: {
                        type: 'shadow',
                    },
                },
            ],
            yAxis: [
                {
                    type: 'value',
                    name: '万元',
                    min: 0,
                    max: 250,
                    interval: 50,
                    axisLabel: {
                        formatter: '{value}',
                    },
                },
            ],
            series: [
                {
                    name: '',
                    type: 'bar',
                    data: [],
                },
            ],
        }

        this.init(wrapperId, data);
    }

    /**
     * 设置图表数据
     * @param {Object} data
     * @param {Array} data.series
     * @param {Array} data.xAxis
     */
    Pillars.prototype.setData = function (data) {
        if (typeof data === 'function') return
        this.option.series[0].data = data.series
        this.option.xAxis[0].data = data.xAxis
        this.option.yAxis[0].max = data.max
        this.option.yAxis[0].interval = data.max / 10
        this.chart.setOption(this.option)
    }

    //收集
    var charts = {
        Ratio: Ratio,
        MoreTrendLine: MoreTrendLine,
        Pillars: Pillars,
    }




    /**
     *
     * 图表公共方法、属性
     */
    function ChartCommon () {
        this.eventsHandlerMap = {} //事件处理
    }

    /**
     * 初始化
     * @param {String} wrapperId
     * @param {*|Function} data
     */
    ChartCommon.prototype.init = function (wrapperId, data) {
        if (!echarts) {
            return console.warn(chartType + '类型的Chart不存在!') 
        }
        var dom = doc.querySelector(wrapperId)
        this.id = 'hr_' + Date.now();
        this.wrapId = wrapperId
        this.chart = echarts.init(dom)
        this.chart.setOption(this.option)
        if (Object.prototype.toString.call(data) === '[object Object]') {
            this.setData(data)
        }
    }

    /**
     * 获取公共参数
     * @return {Object}
     */
    ChartCommon.prototype.setOption = function (newOptions) {
        this.option = newOptions
        this.chart.setOption(newOptions)
        return this;
    }

    /**
     * 图表监听/注册事件
     * @param {Object} events 监听事件类型 例:{click: function () {}}
     * @param {String} events[key] 事件名称
     * @param {Function} events[value] 事件处理方法
     * @return {Object} chart实例
     */
    ChartCommon.prototype.listen = function (events) {
        var _self = this
        Object.keys(events).forEach(function (key) {
            var eventHandle = events[key] //事件处理函数
            _self.chart.on(key, function () {
                var args = [].slice.call(arguments, 0)
                typeof eventHandle === 'function' && eventHandle.apply(_self, args) //事件监听实参请参考Echart文档
            })
        })
        return this
    }

    /**
     * 获取数据
     * @param {Function} cb 回调函数
     * @return {Object}
     */
    ChartCommon.prototype.getData = function (cb) {
        if (typeof this.getDataFn === 'function') {
            this.getDataFn.call(this, cb || this.setData)
        }
        return this
    }

    //export
    win.charts = win.charts || charts;
    win.ChartCommon = win.ChartCommon || ChartCommon;
})(window, document, window.echarts)
chart-factory.js
/*
 * @Description: 图表工厂,用户管理图表的(增、删、改)等操作功能;
 * @Author: Haor
 * @Date: 2021-03-19
 */

;(function (win, echarts) {
    function ChartFactory () {
        this.charts = {} //收集所有的图表
        this.init()
    }
    
    /**
     * 初始化
     */
    ChartFactory.prototype.init = function () {
        if (!echarts) {
            return console.warn('Please introduce the echart library first');
        }

        this.bindResizeEvent()
    }
    
    /**
     * 获取图表数据
     * @return {Object}
     */
    ChartFactory.prototype.getChartsData = function () {
        var charts = this.charts
        Object.keys(charts).forEach(function (cKey) {
            if (typeof charts[cKey].getData === 'function') {
                charts[cKey].getData.call(charts[cKey], charts[cKey].setData)
            }
        })
        return this
    }
    
    /**
     * 批量创建
     * @param {Array} chartList
     * @param {String} chartList.item.type 图表的type
     * @param {String} chartList.item.wrapId 容器
     * @param {String} chartList.item.objKey 返回实例的key
     * @param {Array|Object|Function} chartList.item.data 图表数据,如果为函数,则里面函数请求内容调用cb,传入data
     * @return {Object}
     */
    ChartFactory.prototype.batchCreate = function (chartList) {
        var chartRes = Object.create(null)
        for (var i = 0, len = chartList.length; i < len; i++) {
            var chartItem = chartList[i]
            var chartObj = this.create(
                chartItem.type,
                chartItem.wrapId,
                chartItem.data,
                chartItem.events
            ) //生成图表实例
            chartRes[chartItem.objKey || chartItem.type] = chartObj
        }
        return chartRes
    }
    
    /**
     * 创建图表
     * @param {String} chartType 图表类型
     * @param {String} wrapperId 容器id
     * @param {*|Function} chartData 数据或获取数据函数
     * @param {Object} events 事件监听
     */
    ChartFactory.prototype.create = function (
        chartType,
        wrapperId,
        chartData,
        events
    ) {
        var chartClassMap = {
            //饼图
            RATIO: charts.Ratio,
    
            //走势折线
            MORE_TREND_LINE: charts.MoreTrendLine,
    
            //柱状图
            PILLARS: charts.Pillars,
        }
    
        //传入的type是否在map中存在
        if (!Object.prototype.hasOwnProperty.call(chartClassMap, chartType)) {
            return console.warn(chartType + '类型的Chart不存在!')
        }
    
        //每个图表构造器继承(ChartCommon)
        var chartClass = utils.extend(chartClassMap[chartType], ChartCommon)
    
        //图表实例
        var chartInstance = new chartClass(wrapperId, chartData)
    
        //绑定获取数据方法
        if (typeof chartData === 'function') {
            chartInstance.getDataFn = chartData
        }
    
        //判断事件
        if (Object.prototype.toString.call(events) === '[object Object]') {
            chartInstance.listen(events)
        }
    
        //保存在实例中
        this.charts[wrapperId] = chartInstance
    
        return chartInstance
    }
    
    /**
     * 绑定窗口缩放事件
     * @param cb
     */
    ChartFactory.prototype.bindResizeEvent = function (cb) {
        var handleEvent = utils.debounce(
            function () {
                var charts = this.charts
                for (var key in charts) {
                    if (charts[key].chart) {
                        typeof charts[key].chart.resize && charts[key].chart.resize()
                        cb && cb(charts[key])
                    }
                }
            }.bind(this),
            100
        )
    
        win.addEventListener('resize', handleEvent, false)
    }

    //export
    win.ChartFactory = win.ChartFactory || ChartFactory;
})(window, (echarts || window.echarts));
utils.js
/*
 * @Description: 工具方法
 * @Author: Haor
 * @Date: 2021-03-19
 */

;(function (win) {
    function Utils() {
        this.version = 'V1.0.0'
        this.auth = 'haor';
    }

    /**
     * 继承
     */
    Utils.prototype.extend = function (target, extTarget) {
        //方法
        if (typeof target === 'object') {
            if (extTarget === 'function') {
                extTarget.call(target);
                for (var k in extTarget.prototype) {
                    target.__proto__[k] = extTarget.prototype[k];
                }
            }

            if (typeof extTarget === 'object') {
                for (var k in extTarget) {
                    target[k] = extTarget[k];
                }
            }
        }

        //构造函数
        if (typeof target === 'function') {
            var data = null;
            if (typeof extTarget === 'object') {
                data = extTarget;
            } 
            if (typeof extTarget === 'function') {
                data = extTarget.prototype;
            }
            for (var k in extTarget.prototype) {
                target.prototype[k] = extTarget.prototype[k];
            }
        }
        
        return target;
    }

    /**
     * 防抖函数
     * @param {Function} fn
     * @param {Number} wait
     */
    Utils.prototype.debounce = function (fn, wait) {
        var timer = null;
        wait = wait || 300;
        return function () {
            if (timer) clearTimeout(timer);
            timer = setTimeout(fn.bind(this), wait) 
        }
    }

    //export
    win.utils = win.utils || new Utils();
})(window);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值