uni-app使用echarts图表封装组件
uni-app 加载echarts图表
代码如下:
<template>
<view
class="echarts"
@click="echarts.onClick"
:prop="option"
:change:prop="echarts.update"
>
</view>
</template>
<script>
export default {
name: 'Echarts',
props: {
},
data(){
return {
option:null
}
},
mounted(){
},
methods:{
}
}
</script>
<script module="echarts" lang="renderjs">
export default {
data() {
return {
chart: null,
}
},
mounted() {
if (typeof window.echarts === 'object') {
this.init()
} else {
// 动态引入类库
const script = document.createElement('script')
script.src = 'static/js/echarts.min.js'
script.onload = this.init
document.head.appendChild(script)
}
},
methods: {
//初始化echarts
init() {
this.chart = echarts.init(this.$el)
this.update(this.option)
},
/**
* 监测数据更新
* @param {Object} option
*/
update(option) {
if (this.chart) {
this.chart.setOption(option)
}
}
},
}
}
</script>
自定义图表配置数据引入
ps:因为是自定义所以可以自由配置,但最好设定后做好注释或写好配置文档|ू・ω・` )
<script>
import round from './charts/round.js'// 圆形图表
import doubleColumnLine from './charts/doubleColumnLine.js'// 双柱折线图表
import triangle from './charts/triangle.js'// 倒三角图表
export default {
name: 'Echarts',
props: {
options: {
type: Object,
default() {
return null;
},
},
cardData:{
type:Array,
default:() => { return [] }
},
// 自有数据样式
// round 圆形
cardType:{
type:String,
default:'round'
},
// 主标题
title:{
type:String,
default:null
},
// 副标题
subtitle:{
type:String,
default:null
},
// 颜色
colorArr:{
type:Array,
default:() => { return [] }
},
// 图例名称
nameTheLegend:{
type:Array,
default:() => { return [] }
},
// 图例显示
legend:{
type:Boolean,
default:true
},
},
data(){
return {
option:null
}
},
mounted(){
// 是否使用只有数据
if(this.options == null){
this.option = this.getOption()
this.modifyChartData()
}else{
this.option = Object.assign({}, this.options)
}
},
methods:{
getOption() {
// 这里根据相应的cardType返回不同的默认option
switch (this.cardType) {
case "round":// 圆形图表
return round(this.cardData);
case "doubleColumnLine":// 双柱折线图表
return doubleColumnLine(this.cardData);
case "triangle":// 倒三角图表
return triangle(this.cardData);
default:
break;
}
},
// 修改chart数据
modifyChartData(){
// 这里根据相应的cardType返回不同的默认option
switch (this.cardType) {
case "round":// 圆形图表
// 主标题
if(this.title){
this.option.title.text = this.title
}
// 副标题 超过8个字符换行
if(this.subtitle){
this.option.title.subtext = this.subtitle.length<=8?this.subtitle:this.subtitle.slice(0,8)+'\n'+this.subtitle.slice(8)
}
break
case "doubleColumnLine":// 双柱折线图表
// 颜色
if(this.colorArr.length){
this.option.series.forEach((item,index)=>{
item.itemStyle.normal.color = this.colorArr[index]
})
}
// 图例显示
if(!this.legend){
this.option.legend=null
}
let nameList =[]
// 图例名称
if(this.nameTheLegend.length){
nameList=this.nameTheLegend
}else{
nameList=['总人数','缺勤数','出勤率']
}
if(nameList.length){
this.option.series.forEach((item,index)=>{
item.name = nameList[index]
})
break
default:
break;
}
}
}
}
</script>
以下是option 的js配置代码之一,可供参考
export default (data = [])=>{
data = data.length ? data : [{ name: "暂无1", value1: 25 ,value2: 2,value3: 9}]
// 滚动条长度
const lengthTheScrollBar=data.length>4?Math.round((3/data.length)*100):100
// console.log('lengthTheScrollBar',lengthTheScrollBar)
// 总人数
let totalNumberOf = 0
// 缺勤数
let numberAbsences = 0
data.forEach(item=>{ totalNumberOf += item.value1 })
data.forEach(item=>{ numberAbsences += item.value2 })
// 出勤率
let attendance = ((totalNumberOf-numberAbsences)/totalNumberOf)*100
// 名称字数计算
function titleToCalculate(name){
if(name.length>4){
if(name.length>8){
return name.slice(0,4)+'\n'+name.slice(4,7)+'...'
}else{
return name.slice(0,4)+'\n'+name.slice(4,name.length)
}
}else{
return name
}
}
return {
tooltip: {
trigger: 'axis',
formatter:'{b}<br />{a}: {c0}<br />{a1}: {c1}<br />{a2}: {c2}%'
grid: {
top: 70,
right: 20,
bottom: 30,
left: 20,
containLabel: true
},
dataZoom:lengthTheScrollBar!=100?[
{
type: 'slider',
start: 0,
end: lengthTheScrollBar,
show: 0,
realtime: true,
zoomLock: true,
height: 10,
bottom: '3%'
},
{
type: 'inside',
start: 0,
end: lengthTheScrollBar,
realtime: true,
zoomLock: true,
show: 0,
}
]:null,
legend: {
orient:'horizontal',
icon: 'circle',
x: 'right',
y: 30,
itemWidth: 10,
itemGap: 5,
//注意配置文件中不能使用formatter函数,会包无限递归错误
// formatter: (name) => {
// if(name=='总人数'){
// return name+':'+totalNumberOf+'人'
// }
// if(name=='缺勤数'){
// return name+':'+numberAbsences+'人'
// }
// if(name=='出勤率'){
// return name+':'+attendance.toFixed(1)+'%\t'
// }
// }
},
xAxis: [
{
type: 'category',
data: data.map(item=>titleToCalculate(item.name)),
}
],
yAxis: [
{
type: 'value',
name : '(人数)',
nameTextStyle : {
color : "#000",
padding : [0,30,10,0]
},
axisLabel: {
formatter: '{value} '
},
splitLine: {
show: true,
lineStyle : {
type : 'none'
}
},
axisLine : {
show : false,
lineStyle : {
color : '#CCCCCC',
}
},
axisTick : {
show : false,
}
},
{
type: 'value',
axisLabel: {
formatter: '{value} %'
},
splitLine: {
show: false
},
axisLine : {
show : false,
lineStyle : {
color : '#CCCCCC'
}
},
axisTick : {
show : false,
}
}
],
series: [
{
name: '总人数',
type: 'bar',
barWidth: 10,
data: data.map(item=>item.value1),
itemStyle : {
normal: {
barBorderRadius: [10, 10, 0, 0],
color : '#43B3FF',
},
}
},
{
name: '缺勤数',
type: 'bar',
barWidth: 10,
data: data.map(item=>item.value2),
itemStyle : {
normal: {
barBorderRadius: [10, 10, 0, 0],
color : '#ff5f51',
},
}
},
{
name: '出勤率',
type: 'line',
yAxisIndex: 1,
symbolSize : 5,
data: data.map(item=>item.value3),
itemStyle : {
normal: {
color : '#5FE9A4',
},
}
}
]
}
}
配置文件中不能使用formatter函数,如何自定义想要的chart
<script module="echarts" lang="renderjs">
let functionStr = ''
export default {
data() {
return {
chart: null,
}
},
mounted() {
if (typeof window.echarts === 'object') {
this.init()
} else {
// 动态引入类库
const script = document.createElement('script')
script.src = 'static/js/echarts.min.js'
script.onload = this.init
document.head.appendChild(script)
}
},
methods: {
//初始化echarts
init() {
let _this = this;
this.chart = echarts.init(this.$el)
this.update(this.option)
},
/**
* 监测数据更新
* @param {Object} option
*/
update(option) {
if (this.chart) {
// 因App端,回调函数无法从renderjs外传递,故在此自定义设置相关回调函数
if (option) {
// 设置新的option
switch(option.series[0].type){
case "pie":// 圆形图表
option.series[0].label.normal.formatter=(param)=>{
// console.log(param)
const name = param.name.length > 11 ? param.name.substr(0, 11) + "..." : param.name;
if(param.data.title){
return `${name}\n${param.value}\t\t${param.data.value1}%`;
}
if(param.name.indexOf('率')!=-1){
return `${name}\n${param.value}个\t\t${param.percent}%`;
}else{
return `${name}\n${param.value}\t\t${param.percent}%`;
}
}
functionStr = JSON.stringify(option.series[0].label.normal.formatter)
break
case "bar":// 双柱折线图
if(option.legend&&!option.legend.formatter){
option.legend.formatter=(name)=>{
if(name.indexOf('观看')!=-1){
return name
}
let note=''
let num = 0
option.series.forEach(item=>{
if(item.name==name){
item.data.forEach(each=>{
num+=Number(each)
})
}
})
if(name.indexOf('率')!=-1){
// 总人数
let totalNumberOf = 0
// 缺勤数
let numberAbsences = 0
option.series.forEach((item,index)=>{
item.data.forEach(each=>{
if(index==0){
totalNumberOf+=Number(each)
}else if(index==1){
numberAbsences+=Number(each)
}
})
})
// 出勤率
let attendance = ((totalNumberOf-numberAbsences)/totalNumberOf)*100
note=name+'\t\t'+attendance.toFixed(1)+'%'
}else{
note=name+'\t\t'+num+'人'
}
return note
}
}
break
case "funnel":// 倒三角图表
break
default:
break;
}
this.chart.setOption(option)
}
}
},
}
}
</script>
完整组件代码,及点击事件触发
<template>
<view class="echarts" @click="echarts.onClick" :prop="option" :change:prop="echarts.update"></view>
</template>
<!--
注意: 调用接口用v-if进行数据刷新,接口调用结束v-if=true
使用方式1:
<EncapsulatingChart v-if='flase' cardType="round" :title="'500'" :subtitle="'出勤总人数'" :annotation="annotation"></EncapsulatingChart>
cardType:是自有的一些样式模板 字符串类型 值有 (圆形 'round')
title:标题 字符串类型
subtitle:副标题 字符串类型
//annotation:延伸注释 函数类型
<EncapsulatingChart v-if='flase' cardType="doubleColumnLine" :colorArr="['#828BFF','#FF5F51','#5FE9A4']"></EncapsulatingChart>
cardType:是自有的一些样式模板 字符串类型 值有 (双柱折线图 'doubleColumnLine')
colorArr:颜色 字符串数组类型
nameTheLegend:图例名称 字符串数组类型
<EncapsulatingChart v-if='flase' cardType="triangle" ></EncapsulatingChart>
cardType:是自有的一些样式模板 字符串类型 值有 (倒三角图表 'triangle')
使用方式2: 自有的一些样式模板不满足需求
<EncapsulatingChart v-if='flase' :options="options"></EncapsulatingChart>
options: 自定义chart数据 对象类型
-->
<script>
import round from './charts/round.js'// 圆形图表
import doubleColumnLine from './charts/doubleColumnLine.js'// 双柱折线图表
import triangle from './charts/triangle.js'// 倒三角图表
export default {
name: 'Echarts',
props: {
options: {
type: Object,
default() {
return null;
},
},
cardData:{
type:Array,
default:() => { return [] }
},
// 自有数据样式
// round 圆形
cardType:{
type:String,
default:'round'
},
// 主标题
title:{
type:String,
default:null
},
// 副标题
subtitle:{
type:String,
default:null
},
// 颜色
colorArr:{
type:Array,
default:() => { return [] }
},
// 图例名称
nameTheLegend:{
type:Array,
default:() => { return [] }
},
// 图例显示
legend:{
type:Boolean,
default:true
},
// 图表点击事件
chartClick:{
type:Function,
default:(params)=>{
}
}
},
data(){
return {
option:null
}
},
mounted(){
// 是否使用只有数据
if(this.options == null){
this.option = this.getOption()
this.modifyChartData()
}else{
this.option = Object.assign({}, this.options)
}
},
methods:{
//父级回调
parentCallback(params){
this.$emit('chartClick',params)
},
getOption() {
// 这里根据相应的cardType返回不同的默认option
switch (this.cardType) {
case "round":// 圆形图表
return round(this.cardData);
case "doubleColumnLine":// 双柱折线图表
return doubleColumnLine(this.cardData);
case "triangle":// 倒三角图表
return triangle(this.cardData);
default:
break;
}
},
// 修改chart数据
modifyChartData(){
// 这里根据相应的cardType返回不同的默认option
switch (this.cardType) {
case "round":// 圆形图表
// 主标题
if(this.title){
this.option.title.text = this.title
}
// 副标题 超过8个字符换行
if(this.subtitle){
this.option.title.subtext = this.subtitle.length<=8?this.subtitle:this.subtitle.slice(0,8)+'\n'+this.subtitle.slice(8)
}
break
case "doubleColumnLine":// 双柱折线图表
// 颜色
if(this.colorArr.length){
this.option.series.forEach((item,index)=>{
item.itemStyle.normal.color = this.colorArr[index]
})
}
// 图例显示
if(!this.legend){
this.option.legend=null
}
let nameList =[]
// 图例名称
if(this.nameTheLegend.length){
nameList=this.nameTheLegend
}else{
nameList=['总人数','缺勤数','出勤率']
}
if(nameList.length){
this.option.series.forEach((item,index)=>{
item.name = nameList[index]
})
}
break
default:
break;
}
}
}
}
</script>
<script module="echarts" lang="renderjs">
let functionStr = ''
let asyncClick
export default {
data() {
return {
chart: null,
}
},
mounted() {
if (typeof window.echarts === 'object') {
this.init()
} else {
// 动态引入类库
const script = document.createElement('script')
script.src = 'static/js/echarts.min.js'
script.onload = this.init
document.head.appendChild(script)
}
},
methods: {
//初始化echarts
init() {
let _this = this;
this.chart = echarts.init(this.$el)
this.update(this.option)
this.chart.on('click', function(params){
console.log(params)
asyncClick = params
});
},
/**
* 监测数据更新
* @param {Object} option
*/
update(option) {
if (this.chart) {
// 因App端,回调函数无法从renderjs外传递,故在此自定义设置相关回调函数
if (option) {
// 设置新的option
switch(option.series[0].type){
case "pie":// 圆形图表
option.series[0].label.normal.formatter=(param)=>{
// console.log(param)
const name = param.name.length > 11 ? param.name.substr(0, 11) + "..." : param.name;
if(param.name.indexOf('率')!=-1){
return `${name}\n${param.value}个\t\t${param.percent}%`;
}else{
return `${name}\n${param.value}\t\t${param.percent}%`;
}
}
functionStr = JSON.stringify(option.series[0].label.normal.formatter)
break
case "bar":// 双柱折线图
if(option.legend&&!option.legend.formatter){
option.legend.formatter=(name)=>{
if(name.indexOf('观看')!=-1){
return name
}
let note=''
let num = 0
option.series.forEach(item=>{
if(item.name==name){
item.data.forEach(each=>{
num+=Number(each)
})
}
})
if(name.indexOf('率')!=-1){
// 总人数
let totalNumberOf = 0
// 缺勤数
let numberAbsences = 0
option.series.forEach((item,index)=>{
item.data.forEach(each=>{
if(index==0){
totalNumberOf+=Number(each)
}else if(index==1){
numberAbsences+=Number(each)
}
})
})
// 出勤率
let attendance = ((totalNumberOf-numberAbsences)/totalNumberOf)*100
note=name+'\t\t'+attendance.toFixed(1)+'%'
}else{
note=name+'\t\t'+num+'人'
}
return note
}
}
break
case "funnel":// 倒三角图表
break
default:
break;
}
this.chart.setOption(option)
}
}
},
onClick(event, ownerInstance) {
if (asyncClick) {
let obj = Object.assign({}, asyncClick)
delete obj.event //必须删除这个属性,否则无法传输对象,此字段是元素本身 JSON.stringify 不能转化无限递归对象
ownerInstance.callMethod('parentCallback', obj)
asyncClick = null;
}
},
}
}
</script>
<style lang="scss" scoped>
.echarts {
width: 100%;
height: 100%;
}
</style>
不删除则会包错,错误如下