注意:vue-echarts在使用前要先安装echarts,不要只安装vue-echarts这一个
echarts官网地址:Examples - Apache EChartsApache ECharts,一款基于JavaScript的数据可视化图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表。https://echarts.apache.org/examples/zh/index.html具体安装步骤不清楚的请参考文档:vue3中,vue-echarts基本使用(柱状图、饼图、折线图)_vue3 vue-echarts-CSDN博客文章浏览阅读2.3w次,点赞34次,收藏86次。注意:vue-echarts在使用前要先安装echarts,不要只安装vue-echarts这一个echarts官网地址:Apache ECharts,一款基于JavaScript的数据可视化图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表。安装vue-echarts注意:Vue 2下使用,必须还要安装main.js中全局注册组件。_vue3 vue-echartshttps://blog.csdn.net/mq1314520_zhl/article/details/135554131?fromshare=blogdetail&sharetype=blogdetail&sharerId=135554131&sharerefer=PC&sharesource=mq1314520_zhl&sharefrom=from_link
import { onMounted, reactive, ref, onUnmounted } from 'vue'
import * as echarts from 'echarts'
// 定义变量 图表的渲染
const currentRef = ref(null)
// 定义变量 存储数据
const list = ref([
{
qty: 6416.6,
days: "-3",
materialCode: "4106MF02",
},
{
qty: 2010.0,
days: "-3",
materialCode: "21035822",
},
{
qty: 10001.8,
days: "-3",
materialCode: "4106MF01",
},
{
qty: 235.0,
days: "-3",
materialCode: "63MF0001",
},
{
qty: 5000.0,
days: "5",
materialCode: "4106MF03",
},
{
qty: 3000.0,
days: "8",
materialCode: "21035823",
},
{
qty: 8000.0,
days: "10",
materialCode: "4106MF04",
},
{
qty: 1200.0,
days: "12",
materialCode: "63MF0002",
},
{
qty: 4500.0,
days: "15",
materialCode: "4106MF05",
},
{
qty: 2800.0,
days: "18",
materialCode: "21035824",
},
{
qty: 6500.0,
days: "20",
materialCode: "4106MF06",
},
{
qty: 3200.0,
days: "22",
materialCode: "63MF0003",
},
{
qty: 7800.0,
days: "25",
materialCode: "4106MF07",
},
{
qty: 4200.0,
days: "28",
materialCode: "21035825",
},
{
qty: 5600.0,
days: "30",
materialCode: "63MF0004",
}])
// 用于定义自动hover使用的变量
let autoHoverTimer = null
let currentHoverIndex = 0
let isUserInteracting = false
// 图表的option定义
const renderPieOptions = () => {
return {
tooltip: {
trigger: 'item',
position: function (pos, params, dom, rect, size) {
const tooltipWidth = size.contentSize[0]
const tooltipHeight = size.contentSize[1]
const containerWidth = size.viewSize[0]
const containerHeight = size.viewSize[1]
let x = pos[0]
let y = pos[1]
if (x + tooltipWidth > containerWidth) {
x = containerWidth - tooltipWidth - 10
}
if (y + tooltipHeight > containerHeight) {
y = containerHeight - tooltipHeight - 10
}
x = Math.max(10, x)
y = Math.max(10, y)
return [x, y]
},
backgroundColor: 'rgba(255, 255, 255, 0.95)',
borderColor: '#e8e8e8',
borderWidth: 1,
padding: [12, 16],
textStyle: {
color: '#333',
fontSize: 12
},
extraCssText: 'box-shadow: 0 2px 8px rgba(0,0,0,0.1); border-radius: 4px;',
formatter: function (params) {
const days = Math.abs(params.data.days)
const statusColor = params.data.status === '已过期' ? '#ff4d4f' : '#faad14'
const statusText = params.data.status === '已过期' ?
`${t('common.dueDate')} ${days}${t('summary.day')} ` :
`${t('summary.expirationDate')} ${days}${t('summary.day')} `
return `
${params.name}
${statusText}
${t('summary.materialsQty')}
${params.value.toLocaleString()}
`
}
},
legend: {
orient: 'vertical',
right: 20,
top: 'center',
data: [
{
name: t('common.dueDate'),
icon: 'circle',
textStyle: {
color: '#ff4d4f',
fontWeight: 'bold'
}
},
{
name: t('summary.nearexpiration'),
icon: 'circle',
textStyle: {
color: '#faad14',
fontWeight: 'bold'
}
},
{
name: t('summary.Normal'),
icon: 'circle',
textStyle: {
color: '#52c41a',
fontWeight: 'bold'
}
}
],
formatter: function (name) {
return name
},
textStyle: {
color: '#666',
fontSize: 12
}
},
series: [
{
name: t('summary.MaterialStatus'),
type: 'pie',
radius: ['20%', '70%'],
center: ['50%', '50%'],
roseType: 'radius',
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 8,
borderColor: '#fff',
borderWidth: 2,
color: function(params) {
const colorMap = {
'已过期': new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#ff4d4f' },
{ offset: 1, color: '#ff7875' }
]),
'临期': new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#faad14' },
{ offset: 1, color: '#ffd666' }
]),
'正常': new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#52c41a' },
{ offset: 1, color: '#95de64' }
])
}
return colorMap[params.data.status]
}
},
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(13,240,248,0.6)'
},
label: {
show: true,
fontSize: 14,
fontWeight: 'bold'
}
},
label: {
show: true,
formatter: function (params) {
const days = Math.abs(params.data.days)
const status = params.data.status === '已过期' ?
`${t('common.dueDate')} ${days}${t('summary.day')} ` :
`${t('summary.expirationDate')} ${days}${t('summary.day')} `
return `{name|${params.name}}\n{value|${params.value.toLocaleString()}}\n${status}`
},
rich: {
name: {
fontSize: 14,
lineHeight: 20,
color: '#333',
fontWeight: 500
},
value: {
fontSize: 14,
lineHeight: 20,
color: '#666'
},
expired: {
fontSize: 12,
lineHeight: 20,
color: '#ff4d4f',
fontWeight: 500
},
warning: {
fontSize: 12,
lineHeight: 20,
color: '#faad14',
fontWeight: 500
}
}
},
labelLine: {
show: true,
length: 10,
length2: 10
},
data: processedData
}
],
graphic: [
{
type: "text",
left: "center",
top: "85%",
style: {
text: "点击图例可筛选显示",
fontSize: 12,
fill: "#999",
},
},
],
}
}
// 动态处理数据 ,如果是从接口处获取数据就将里面的代码放置在接口返回成功赋值的地方
const processedData = list.value.map((item) => {
const days = parseInt(item.days);
let status = "";
let color = "";
let statusClass = "";
if (days < 0) {
status = "已过期";
color = "#ff4d4f";
statusClass = "status-expired";
} else if (days <= 30) {
status = "临期";
color = "#faad14";
statusClass = "status-warning";
} else {
status = "正常";
color = "#52c41a";
statusClass = "status-normal";
}
return {
name: item.materialCode,
value: item.qty,
days: days,
status: status,
statusClass: statusClass,
itemStyle: {
color: color,
},
};
});
// 自动hover效果
const startAutoHover = () => {
if (autoHoverTimer) {
clearInterval(autoHoverTimer)
}
autoHoverTimer = setInterval(() => {
if (!isUserInteracting && currentRef.value && list.value.length > 0) {
// 先取消所有高亮
currentRef.value.dispatchAction({
type: 'downplay',
seriesIndex: 0
})
currentHoverIndex = (currentHoverIndex + 1) % list.value.length
// 显示tooltip
currentRef.value.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: currentHoverIndex
})
// 高亮当前项
currentRef.value.dispatchAction({
type: 'highlight',
seriesIndex: 0,
dataIndex: currentHoverIndex
})
}
}, 2000)
}
// 处理用户交互
const handleUserInteraction = () => {
isUserInteracting = true
if (autoHoverTimer) {
clearInterval(autoHoverTimer)
}
// 用户停止交互后3秒重新开始自动hover
setTimeout(() => {
isUserInteracting = false
startAutoHover()
}, 3000)
}
onMounted(async () => {
if (currentRef.value) {
currentRef.value.setOption(renderPieOptions())
// 添加图表事件监听
currentRef.value.$el.addEventListener('mouseover', handleUserInteraction)
currentRef.value.$el.addEventListener('mouseout', handleUserInteraction)
startAutoHover()
} else {
setTimeout(() => {
if (currentRef.value) {
currentRef.value.setOption(renderPieOptions())
// 添加图表事件监听
currentRef.value.$el.addEventListener('mouseover', handleUserInteraction)
currentRef.value.$el.addEventListener('mouseout', handleUserInteraction)
startAutoHover()
}
}, 100)
}
})
onUnmounted(() => {
if (autoHoverTimer) {
clearInterval(autoHoverTimer)
}
if (currentRef.value) {
currentRef.value.$el.removeEventListener('mouseover', handleUserInteraction)
currentRef.value.$el.removeEventListener('mouseout', handleUserInteraction)
}
})
注意:在vue3中,我们为图表添加鼠标移入移除事件的时候,不能按照以前的惯性思维添加,需要使用到 $el 来获取并添加 ,handleUserInteraction:表示用户自定义的交互 函数
// 鼠标移入
currentRef.value.$el.addEventListener('mouseover', handleUserInteraction)
// 鼠标移出
currentRef.value.$el.addEventListener('mouseout', handleUserInteraction)