<template>
<div :id="echartsId"></div>
</template>
<script setup>
import * as echarts from 'echarts'
import { reactive, ref, onMounted, defineProps, watch, onUnmounted } from 'vue'
const props = defineProps({
echartsBool: {
type: Boolean,
default: false,
},
echartsId: {
type: String,
default: 'echartsId',
},
// 柱状宽度
echartsBarWidth: {
type: String,
default: '30%',
},
// x轴数据
xAxisDataJson: {
type: Array,
default: () => {
return []
},
},
// y轴数据
yAxisJson: {
type: Object,
default: () => {
return {
name: '单位:数量',
}
},
},
// y轴字体样式
nameTextStyle: {
type: Object,
default: () => {
return {
color: '#fff',
fontSize: 14,
fontWeight: 400,
verticalAlign: 'bottom',
// 左上字体位置
padding: [0, -20, 10, 20],
fontFamily: 'PingFang SC',
}
},
},
// 柱状图颜色
barColorJson: {
type: Object,
default: () => {
return {
headColor1: 'rgba(43,194,195,1)',
headColor2: 'rgba(43,194,195,0.5)',
upBarColor: 'rgba(30,70,76,0.5)',
bottomBarColor1: 'rgba(43,194,195,1)',
bottomBarColor2: 'rgba(43,194,195,0.5)',
topColor: 'rgba(30,70,76,1)',
}
},
},
// 数据展示
dataList: {
type: Array,
default: () => {
return [
{
name: '公司1',
value: 73,
max: 100,
},
{
name: '公司2',
value: 18,
max: 100,
},
{
name: '公司3',
value: 43,
max: 100,
},
{
name: '公司4',
value: 66,
max: 100,
},
]
},
},
// legend方向
legendDirection: {
type: Object,
default: () => {
return {
bottom: '0',
top: '0',
left: '0',
right: '0',
}
},
},
// grid方向
gridDirection: {
type: Object,
default: () => {
return {
bottom: '35',
top: '25%',
right: '0%',
left: '10%',
}
},
},
// dataListLength 大小==长度约束柱状宽度 定时器==个数 两个不会同时出现大小暂时不用
dataListLength: {
type: Number,
default: 8,
},
})
const dataKey = reactive(['topData', 'bottomBar', 'bottomCircle', 'middleCircle', 'upBar'])
const dataJson = ref({
topData: [], // 头部数据
bottomBar: [], // 底部立体柱子
bottomCircle: [], // 底下圆片
middleCircle: [], // 中间圆片
upBar: [], // 上边的柱子
})
const dataClear = () => {
dataKey.forEach((el) => {
dataJson.value[el] = []
})
}
const initDataAction = () => {
dataClear()
props.dataList.forEach((item) => {
dataJson.value.topData.push({
name: '',
value: item.max,
symbolPosition: 'end',
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(
0,
0,
0,
1,
[
{
offset: 0,
color: props.barColorJson.topColor,
},
{
offset: 1,
color: props.barColorJson.topColor,
},
],
false
),
},
},
})
dataJson.value.bottomBar.push({
value: item.value,
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(
1,
0,
0,
0,
[
{
offset: 0,
color: props.barColorJson.bottomBarColor1,
},
{
offset: 1,
color: props.barColorJson.bottomBarColor2,
},
],
false
),
},
},
name: item.name,
})
dataJson.value.bottomCircle.push({
name: item.name,
value: item.max,
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(
1,
0,
0,
0,
[
{
offset: 0,
color: props.barColorJson.headColor1,
},
{
offset: 1,
color: props.barColorJson.headColor2,
},
],
false
),
},
},
})
dataJson.value.middleCircle.push({
name: item.name,
value: item.value,
symbolPosition: 'end',
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(
1,
0,
0,
0,
[
{
offset: 0,
color: props.barColorJson.headColor1,
},
{
offset: 1,
color: props.barColorJson.headColor2,
},
],
false
),
},
},
})
dataJson.value.upBar.push({
name: item.name,
value: item.max - item.value,
itemStyle: {
normal: {
color: props.barColorJson.upBarColor,
},
},
})
})
}
const option = ref({
backgroundColor: 'transparent',
dataZoom: [
{
show: false, // 是否显示滑动条
xAxisIndex: 0, // 表示从X轴的零刻度线开始的
startValue: 0, // 数据窗口范围的起始数值
endValue: props.dataListLength - 1, // 数据窗口范围的结束数值(一次性展示几个)
},
],
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(43,194,195,0.5)',
borderColor: 'rgba(43,194,195,1)',
borderWidth: 2,
padding: 5,
textStyle: {
color: 'rgba(43,194,195,1)',
fontSize: 18,
width: 300,
height: 40,
},
formatter: function (params) {
let tooltipBox = ''
tooltipBox += '<div>' + params.name + '</div>'
tooltipBox += '<div>' + params.seriesName + ':' + params.value + '%</div>'
return tooltipBox
},
// formatter: '{c}' + '%',
extraCssText: 'box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);',
// 自定义的 CSS 样式
},
grid: {
right: props.gridDirection.right,
top: props.gridDirection.top,
bottom: props.gridDirection.bottom,
left: props.gridDirection.left,
},
// 设置图例
legend: {
icon: 'roundRect',
show: true,
data: ['得分率'],
textStyle: {
color: '#fff',
fontSize: '14',
},
top: props.legendDirection.top,
bottom: props.legendDirection.bottom,
left: props.legendDirection.left,
right: props.legendDirection.right,
},
xAxis: {
type: 'category',
data: props.xAxisDataJson,
axisTick: {
show: true,
type: 'value',
//文字在刻度中间
alignWithLabel: true,
},
axisLine: {
show: true,
},
// 字体样式
axisLabel: {
show: true,
textStyle: {
color: '#fff',
fontSize: 12,
},
lineHeight: '50', // 行高
interval: 0,
rotate: -45,
formatter: function (value) {
// 当文字长度大于2时,使用slice方法截取字符串并拼接省略号;否则直接返回原文字
if (value.length > 5) {
return `${value.slice(0, 5)}...`
} else {
return value
}
},
},
},
yAxis: {
type: 'value',
name: props.yAxisJson.name,
nameTextStyle: props.nameTextStyle,
max: 100,
splitLine: {
show: true,
lineStyle: {
type: 'dashed', // 将轴线设置为虚线
color: '#35414C',
},
},
axisTick: {
show: true,
},
axisLine: {
show: true,
},
axisLabel: {
show: true,
// 字体样式
color: '#fff', //更改坐标轴文字颜色
fontSize: 12, //更改坐标轴文字大小
},
},
// 宽高
// symbolSize: [20, 5],
// xy偏移
// symbolOffset: [0, -3],
// label 展示
//silent
series: [
// 头
{
name: '得分率',
type: 'pictorialBar',
// 做了滚动暂时不用了
// symbolSize: props.dataList?.length > props.dataListLength ? ['30%', '4.5%'] : [30, 6],
symbolSize: [30, 6],
symbolOffset: [0, -3],
z: 12,
data: dataJson.value.topData,
itemStyle: {
color: 'rgba(43,194,195,0.7)', // 设置图标颜色为红色
},
silent: true,
},
//底部立体柱
{
name: '得分率',
stack: '1',
type: 'bar',
silent: false,
// 做了滚动暂时不用了
// barWidth: props.dataList?.length > props.dataListLength ? props.echartsBarWidth : 30,
barWidth: 30,
data: dataJson.value.bottomBar,
itemStyle: {
normal: {
color: {
x: 1,
y: 0,
x2: 0,
y2: 0,
type: 'linear',
global: false,
colorStops: [
{
//第一节下面
offset: 0,
color: 'rgba(43,194,195,0.5)',
},
{
offset: 1,
color: '#2BC2C3',
},
],
},
},
},
},
//最底下的圆片
{
name: '得分率',
type: 'pictorialBar',
// 做了滚动暂时不用了
// symbolSize: props.dataList?.length > props.dataListLength ? ['30%', '5%'] : [30, 8],
symbolSize: [30, 8],
symbolOffset: [0, 3],
z: 12,
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: 'rgba(43,194,195,1)',
},
{
offset: 1,
color: 'rgba(43,194,195,1)',
},
]),
},
},
data: dataJson.value.bottomCircle,
silent: true,
},
// 中间圆片
{
name: '得分率',
type: 'pictorialBar',
// 做了滚动暂时不用了
// symbolSize: props.dataList?.length > props.dataListLength ? ['30%', '5%'] : [30, 8],
symbolSize: [30, 8],
symbolOffset: [0, -3],
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(
0,
0,
0,
1,
[
{
offset: 0,
color: 'rgba(43,194,195,1)',
},
{
offset: 1,
color: 'rgba(43,194,195,1)',
},
],
false
),
},
},
z: 12,
data: dataJson.value.middleCircle,
},
//上部立体柱
{
name: '得分率',
stack: '1',
type: 'bar',
itemStyle: {
normal: {
color: 'rgba(43,194,195,1)',
opacity: 0.7,
},
},
// 顶部展示
// label: {
// show: true,
// position: "top", //top / left / right / bottom / inside / insideLeft / insideRight / insideTop / insideBottom / insideTopLeft / insideBottomLeft / insideTopRight / insideBottomRight
// distance: 20,
// color: "#FFFE00",
// fontSize: 30,
// formatter: function (item) {
// var a = 100;
// return a - item.value + "%";
// },
// },
silent: true,
// 做了滚动暂时不用了
// barWidth: props.dataList?.length > props.dataListLength ? props.echartsBarWidth : 30,
barWidth: 30,
data: dataJson.value.upBar,
},
],
})
let bar = ''
const initData = () => {
// datalist操作
initDataAction()
option.value.series?.forEach((el, index) => {
el.data = dataJson.value[dataKey[index]]
})
option.value.xAxis.data = []
option.value.xAxis.data = props.xAxisDataJson
// 设置配置项
bar.setOption(option.value)
window.addEventListener('resize', bar.resize)
if (props.dataList.length > props.dataListLength - 1) {
startAnimation()
}
}
let timer = '' // 定时器
const stopAnimation = () => {
clearInterval(timer)
timer = null
}
// 通过datalist进行长度判断是否滚动
const startAnimation = () => {
timer = setInterval(() => {
// 每次向后滚动一个,最后一个从头开始
if (option.value.dataZoom[0].endValue === props.dataList?.length - 1) {
option.value.dataZoom[0].startValue = 0 // 数据窗口范围的起始数值
option.value.dataZoom[0].endValue = props.dataListLength - 1 // 数据窗口范围的结束数值
} else {
option.value.dataZoom[0].startValue = option.value.dataZoom[0].startValue + 1 // 数据窗口范围的起始数值
option.value.dataZoom[0].endValue = option.value.dataZoom[0].endValue + 1 // 数据窗口范围的结束数值
}
bar.setOption(option.value)
}, 3000)
}
onMounted(() => {
let chartDom = document.getElementById(`${props.echartsId}`)
bar = echarts.init(chartDom)
initData()
})
onUnmounted(() => {
stopAnimation()
})
watch(
() => props.echartsBool,
() => {
// 清除之前的视图
bar.clear()
stopAnimation()
initData()
}
)
</script>
效果: