以前云桌面项目写的,功能不多,但是适配基础的柱图和线图完全够了,还可以优化或者拓展很多,后面用vue3开发某个项目的时候有基于这个做过完善和拓展,不过就不是v2的组件了
若有用到,可自行完善
- html和css部分
<template>
<div ref="myChars" class="com-bar-chart" />
</template>
<style scoped>
.com-bar-chart {
width: 100%;
height: 100%;
}
</style>
- js部分
<script>
import * as echarts from 'echarts'
export default {
name: 'EchartLineBar',
props: {
// 数据,数据结构就为数组对象结构[{key1:'', key2:'', key3:'',...},{}]
sourceData: {
type: Array,
default: () => []
},
// echarts配置[{field: '', name: '', color: '', type: 'line',...}, {}]
// 多个对象代表多个线或柱
// field(字段名),name(series的名字),color(颜色,可单个,可数组两值渐变),type(图类型)
seiresConfig: {
type: Array,
default: () => []
},
// grid位置
grid: {
type: Object,
default() {
return {}
}
},
// 值轴配置,可以双值轴
yAxisList: {
type: Array,
default() {
return []
}
},
// 类目轴配置
xAxis: {
type: Object,
default() {
return {}
}
},
// 颜色
colors: {
type: Array,
default: () => ['#0EECE4', '#306FFF']
},
// legend配置
legendConfig: {
type: Object,
default() {
return {}
}
},
titleConfig: {
type: Object,
default() {
return {}
}
},
dataZoom: {
type: [Object, Array],
default: () => {}
},
// 是否X轴作为类目轴
xCategory: {
type: Boolean,
default: true
},
// 是否展示tooltip
tooltip: {
type: Object,
default() {
return {}
}
},
// 是否需要点击折线图的线条返回索引
isClickLine: {
type: Boolean,
default: false
},
// 定时器重复渲染,秒数,为0则不重复渲染
isInfinite: {
type: [Number, String],
default: 0
}
},
data() {
return {
curCharts: null,
timer: null
}
},
computed: {
watchData() {
return {
data: this.sourceData,
config: this.seiresConfig
}
}
},
watch: {
watchData: {
handler() {
this.drawChart()
},
deep: true
}
},
mounted() {
this.drawChart()
},
methods: {
_map(data, field) {
return data.map((item) => (item[field] || '--'))
},
drawChart() {
this.curCharts = echarts.init(this.$refs.myCharts, undefined, { renderer: 'canvas' })
const legends = []
// 处理数据
// 传入原始数据处理
const seriesList = this.seiresConfig
// .filter((item) => !!item.field)
.map((item, index) => {
legends.push({
name: item.name,
itemStyle: {
color: item.color ? (typeof item.color === 'string' ? item.color : item.color[0]) : '#fff'
}
})
const obj = {
name: item.name || '',
// 为了适配传入的series的data模式为对象模式,条件是type为bar
data:
!item.colors || item.colors.length === 0
? this._map(this.sourceData, item.field || 'value')
: this.sourceData.map((sitem, sindex) => {
const sobj = {
name: sitem.name || '',
value: sitem[item.field || 'value'],
barWidth: item.barWidth || 6,
barGap: item.barGap || '30%',
z: item.z || '1',
itemStyle: {},
label: {}
}
if (item.type === 'bar') {
sobj.itemStyle = {
color:
typeof item.colors[sindex % item.colors.length] === 'string'
? item.colors[sindex % item.colors.length]
: new echarts.graphic.LinearGradient(0, 0, this.xCategory ? 0 : 1, this.xCategory ? 1 : 0, [
{
offset: 0,
color: item.colors[sindex % item.colors.length][0],
opacity: 0.85
},
{
offset: 1,
color: item.colors[sindex % item.colors.length][1],
opacity: 0.79
}
])
}
sobj.label = {
color:
typeof item.colors[0] === 'string'
? item.colors[sindex % item.colors.length]
: item.colors[sindex % item.colors.length][0],
...item.label
}
}
return sobj
}),
type: item.type || 'line',
yAxisIndex: item.yAxisIndex || 0,
stack: item.stack || '',
label: {
show: false,
fontSize: 14,
position: 'top',
color: item.color ? (typeof item.color === 'string' ? item.color : item.color[0]) : '#fff',
...item.label
}
}
if (!item.type || item.type === 'line') {
obj.smooth = item.smooth || true
obj.symbol = item.symbol || 'circle'
obj.symbolSize = item.symbolSize || 10
obj.itemStyle = {
color: item.color || (this.colors.length > 0 ? this.colors[index % this.colors.length] : '#fff'),
borderWidth: ((item.symbolSize || 10) / 4).toFixed(0),
borderColor: '#fff'
}
obj.lineStyle = {
width: item.lineWidth || 2,
type: item.lineType || 'solid',
color: item.color || (this.colors.length > 0 ? this.colors[index % this.colors.length] : '#fff')
}
// 线条填充区域
if (item.areaColor) {
obj.areaStyle = {
color:
typeof item.areaColor === 'string'
? item.areaColor
: new echarts.graphic.LinearGradient(0, 0, this.xCategory ? 0 : 1, this.xCategory ? 1 : 0, [
{
offset: 0,
color: item.areaColor[0]
},
{
offset: 1,
color: item.areaColor[1]
}
])
}
}
} else {
obj.barWidth = item.barWidth || 6
obj.barGap = item.barGap || '30%'
obj.z = item.z || '1'
// bar的颜色,判断不存在就用props中的颜色,如果单个字符串,就为纯色,否则数组两个颜色渐变
obj.itemStyle = {
color: item.color
? typeof item.color === 'string'
? item.color
: new echarts.graphic.LinearGradient(0, 0, this.xCategory ? 0 : 1, this.xCategory ? 1 : 0, [
{
offset: 0,
color: item.color[0],
opacity: 0.85
},
{
offset: 1,
color: item.color[1],
opacity: 0.79
}
])
: this.colors.length > 0
? this.colors[index % this.colors.length]
: '#fff'
}
}
return obj
})
// console.log(seriesList,'1111');
// 定义渲染参数
const option = {
tooltip: {
trigger: 'axis',
confine: true,
padding: [5, 10],
borderColor: '#25324F',
backgroundColor: '#25324F',
axisPointer: {
// 鼠标移入坐标指示器
type: 'cross',
animation: false,
label: {
backgroundColor: '#505765'
}
},
show: true,
extraCssText: 'border-radius: 2px;',
textStyle: {
color: '#ffffff',
fontSize: 14
},
formatter: (params) => {
let result = ''
if (Object.prototype.toString.call(params) === '[object Object]') {
params = [params]
}
params = params.filter((item) => item.seriesName !== 'noTooltip' && item.data !== '-')
// 处理尺寸大小问题
for (const item of params) {
const dotHtml = `<span style="display:inline-block;margin-right:3px;border-radius:${8}px;height:${8}px;width:${8}px;background-color:${
item.seriesType === 'line'
? item.color || item.borderColor
: typeof item.color === 'string'
? item.color
: item.color.colorStops[0].color
}"></span>`
result += `</br>${dotHtml}${item.seriesName || ''} ${item.value || 0}`
}
return (params[0].axisValue || params[0].name || '') + result
},
...this.tooltip
},
color: this.colors,
title: {
...this.titleConfig
},
grid: {
top: 30,
bottom: 25,
left: 25,
right: 10,
...this.grid
},
legend: {
data: legends,
top: 5,
right: 10,
itemGap: 10,
itemWidth: 10,
itemHeight: 10,
itemStyle: {
// color:,
borderWidth: 0
},
lineStyle: {
width: 5
},
orient: 'horizontal', // vertical:纵向 horizontal: 横向
textStyle: {
color: '#fff',
fontSize: 14,
padding: [0, 0, 0, 5]
},
...this.legendConfig
},
animationDuration: 2000,
series: seriesList
}
if (this.dataZoom) {
option.dataZoom = this.dataZoom
}
// 类目对象属性
const categoryObj = {
type: 'category',
scale: true,
boundaryGap: true, //两边是否留白
data: this._map(this.sourceData, 'name'),
// nameGap: 90, // 坐标轴名称与轴线之间的距离
...this.xAxis,
...{
axisLine: {
show: false,
lineStyle: {
width: 2,
color: '#fff'
},
...(this.xAxis.axisLine || {})
},
minorTick: {
lineStyle: {
color: 'rgba(255,255,255,0.2)'
},
...(this.xAxis.minorTick || {})
},
axisTick: {
show: false,
length: 5,
inside: true, // 朝内
lineStyle: {
width: 7
},
...(this.xAxis.axisTick || {})
},
axisLabel: {
show: true,
fontSize: 14,
color: '#ffffff',
margin: 10,
// overflow: 'truncate',
// interval: 0,
...(this.xAxis.axisLabel || {})
},
axisPointer: {
// 鼠标移入坐标指示器
type: 'line',
lineStyle: {
type: 'dashed'
},
...(this.xAxis.axisPointer || {})
}
}
}
// 值轴属性
const valueObj = []
if (this.yAxisList && this.yAxisList.length > 0) {
this.yAxisList.map((item) => {
valueObj.push({
type: 'value',
// splitNumber: 5, // 分几个区间
...item,
...{
nameTextStyle: {
fontSize: 14,
color: '#fff',
align: 'center',
padding: [0, 0, 0, 0],
...(item.nameTextStyle || {})
},
axisLine: {
show: false,
lineStyle: {
width: 1,
color: '#fff'
},
...(item.axisLine || {})
},
axisLabel: {
formatter: '{value}',
margin: 4,
textStyle: {
color: '#fff',
fontSize: 14
},
...(item.axisLabel || {})
},
splitLine: {
show: true,
lineStyle: {
type: 'dashed',
width: 1,
color: 'rgba(255,255,255,0.1)'
},
...(item.splitLine || {})
}
}
})
})
}
if (this.xCategory) {
option.xAxis = categoryObj
option.yAxis = valueObj
} else {
option.xAxis = valueObj
option.yAxis = categoryObj
}
if (valueObj.length > 0) {
this.curCharts.setOption(option)
if (this.isClickLine) {
// 如果需要点击折现也回调,则使用下面的方法
this.curCharts.getZr().on('click', (item) => {
let index = 0
if (item.target) {
index = item.target.parent.parent['__ecComponentInfo'].index || 0
this.$emit('itemClick', index)
}
})
} else {
// 普通柱子和折现的点点击回调
this.curCharts.on('click', (item) => {
this.$emit('itemClick', item)
})
}
}
// 定时器,循环播放动画
if (this.isInfinite > 0) {
this.timer = setInterval(() => {
this.curCharts.clear()
this.curCharts.setOption(option)
}, Number(this.isInfinite) * 1000)
}
}
},
beforeDestroy() {
clearInterval(this.timer)
}
}
</script>
- 示例
临时加的示例,若有问题请自行修正,很久以前的云桌面项目中写的了,没有项目源码
多个图若配置差不多,甚至于可以就用同一个配置,不同的config
list仅仅是为了demo数据,实际对接接口的时候可以单独提出来传入,如第二个图
<template>
<EchartLineBar
:tooltip="chartConfig.tooltip"
:grid="chartConfig.grid"
:legendConfig="chartConfig.legend"
:sourceData="chartConfig.list"
:seiresConfig="chartConfig.config"
/>
<EchartLineBar
:tooltip="chartConfig.tooltip"
:grid="chartConfig.grid"
:legendConfig="chartConfig.legend"
:dataZoom="chartConfig.dataZoom"
:sourceData="lineData"
:seiresConfig="chartConfig.configLine"
/>
</template>
<script>
export default {
data() {
return {
// 第二个线图数据
lineData: [
{ name: '四川省', value: 985, value2: 830 },
{ name: '广东省', value: 8, value2: 8 },
{ name: '江苏省', value: 5, value2: 12 },
],
// 线图和柱图的共有配置
chartConfig: {
tooltip: {
show: true
},
grid: {
top: 40,
bottom: 50,
},
legend: {
icon: 'rect',
show: true,
itemWidth: 16,
itemHeight: 16,
left: 'center',
top: 7,
textStyle: {
padding: 25,
color: '#FFF',
fontSize: 17
}
},
config: [
{
name: '迁入',
type: 'bar',
field: 'value',
barWidth: 25,
color: ['#A5DB0D', '#05D23F'],
label: {
show: true,
position: 'top'
},
},
{
name: '迁出',
type: 'bar',
field: 'value2',
barWidth: 25,
color: ['#ECBB0E', '#E78D05'],
label: {
show: true,
position: 'top'
},
},
],
configLine: [
{
name: '水位',
field: 'z',
color: '#2082e6',
symbol: 'none',
areaColor: ['#64a7eb', '#64a7eb36']
},
{
name: '流量',
field: 'q',
yAxisIndex: 1,
color: '#26e3d6',
symbol: 'none'
},
{
name: '警戒水位',
field: 'wrz',
color: '#ffdd98',
symbol: 'none',
lineType: 'dashed'
},
],
dataZoom: {
show: true,
height: 10,
bottom: 40,
start: 0,
end: 100,
handleIcon:
'path://M306.1,413c0,2.2-1.8,4-4,4h-59.8c-2.2,0-4-1.8-4-4V200.8c0-2.2,1.8-4,4-4h59.8c2.2,0,4,1.8,4,4V413z',
handleStyle: {
color: '#d3dee5'
}
},
list: [
{ name: '四川省', value: 985, value2: 830 },
{ name: '广东省', value: 8, value2: 8 },
{ name: '江苏省', value: 5, value2: 12 },
{ name: '山东省', value: 4, value2: 12 },
{ name: '重庆市', value: 4, value2: 6 },
{ name: '甘肃省', value: 4, value2: 0 },
{ name: '陕西省', value: 3, value2: 1 },
{ name: '北京市', value: 2, value2: 0 },
{ name: '浙江省', value: 2, value2: 12 },
{ name: '贵州省', value: 2, value2: 0 },
{ name: '西藏', value: 2, value2: 1 },
{ name: '上海市', value: 1, value2: 2 },
{ name: '福建省', value: 1, value2: 20 },
{ name: '湖北省', value: 1, value2: 0 },
{ name: '湖南省', value: 1, value2: 1 },
{ name: '云南省', value: 1, value2: 0 },
{ name: '新疆', value: 1, value2: 0 },
{ name: '河南省', value: 0, value2: 7 },
{ name: '天津市', value: 1, value2: 2 },
{ name: '河北省', value: 2, value2: 1 },
{ name: '安徽省', value: 3, value2: 1 },
{ name: '宁夏', value: 4, value2: 1 },
]
}
}
},
}
</script>