最近公司写几个报表模块,抽出空余时间简单的封装了一下。对原始的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);