文章目录

    • 概要
    • 技术细节
    • 效果

概要

需求需要实现图例移入显示描述说明
故实现自定义图例

技术细节

<template><div class="custom-legend"><divv-for="item in legends":key="item.name"class="legend-item":class="{ 'is-disabled': !isItemActive(item.name) }"@click="toggleLegend(item)"><spanclass="legend-marker":style="{ backgroundColor: item.color }"></span><a-tooltip><template #title><span>{{ item.tooltip || item.name }}</span></template><span>{{ item.name }}</span></a-tooltip></div></div>
</template><script setup>
import { ref, computed, watch, onMounted, onBeforeUnmount } from 'vue'const props = defineProps({chartInstance: {type: Object,default: () => null},customTooltips: {type: Object,default: () => ({})}
})const legends = ref([])
const activeMap = ref({})const isItemActive = computed(() => (name) => {return activeMap.value[name]
})const toggleLegend = (item) => {if (!props.chartInstance) returnconst name = item.nameconst newState = !activeMap.value[name]activeMap.value = { ...activeMap.value, [name]: newState }props.chartInstance.setOption({legend: {selected: activeMap.value}})
}const renderLegends = () => {if (!props.chartInstance) {legends.value = []return}const chart = props.chartInstanceconst options = chart.getOption()const { series, color: globalColors, legend } = optionsconst chartSelectedMap = legend?.[0]?.selected || {}activeMap.value = { ...chartSelectedMap }const legendItems = []series.forEach((seriesItem, seriesIndex) => {if (seriesItem.type === 'pie') {seriesItem.data.forEach((dataItem, dataIndex) => {const name = dataItem.nameconst color =dataItem.itemStyle?.color ||globalColors[dataIndex % globalColors.length] ||'#000'if (activeMap.value[name] === undefined) {activeMap.value[name] = true}legendItems.push({name,color,tooltip: props.customTooltips[name] || name})})} else {const name = seriesItem.nameconst color =seriesItem.itemStyle?.color ||globalColors[seriesIndex % globalColors.length] ||'#000'if (activeMap.value[name] === undefined) {activeMap.value[name] = true}legendItems.push({name,color,tooltip: props.customTooltips[name] || name})}})legends.value = legendItems
}const handleChartLegendChange = (params) => {activeMap.value = { ...params.selected }
}watch(() => props.chartInstance,(newVal) => {if (newVal) {renderLegends()} else {legends.value = []}},{ immediate: true }
)
</script><style scoped lang="scss">
.custom-legend {display: flex;flex-wrap: wrap;justify-content: center;gap: 12px;padding: 8px;.legend-item {display: flex;align-items: center;gap: 6px;cursor: pointer;transition: all 0.2s ease;.legend-marker {width: 14px;height: 14px;border-radius: 50%;transition: all 0.2s ease;}&.is-disabled {opacity: 0.6;.legend-marker {filter: grayscale(100%);transform: scale(0.9);}}&:hover:not(.is-disabled) {transform: translateY(-1px);opacity: 0.9;}}
}
</style>
<template><div class="container"><div class="chart" ref="lineChart"></div><div class="chart" ref="pieChart"></div><div class="legend1"><Legend :chartInstance="chartInstance1" /></div><div class="legend2"><Legend :chartInstance="chartInstance2" /></div></div>
</template>
<script setup>
import * as echarts from 'echarts'
import Legend from './components/Legend.vue'const lineChart = ref(null)
const pieChart = ref(null)const chartInstance1 = shallowRef(null)
const chartInstance2 = shallowRef(null)const _data = {line: {title: '折线图示例',categories: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],legend: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎'],series: [{name: '邮件营销',type: 'line',data: [120, 132, 101, 134, 90, 230, 210]},{name: '联盟广告',type: 'line',data: [220, 182, 191, 234, 290, 330, 310]},{name: '视频广告',type: 'line',data: [150, 232, 201, 154, 190, 330, 410]},{name: '直接访问',type: 'line',data: [320, 332, 301, 334, 390, 330, 320]},{name: '搜索引擎',type: 'line',data: [820, 932, 901, 934, 1290, 1330, 1320]}]},pie: {title: '饼图示例',legend: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎'],series: [{ value: 335, type: 'pie', name: '直接访问' },{ value: 310, type: 'pie', name: '邮件营销' },{ value: 234, type: 'pie', name: '联盟广告' },{ value: 135, type: 'pie', name: '视频广告' },{ value: 1548, type: 'pie', name: '搜索引擎' }]}
}const onItemClick = (params) => {chartInstance1.value.dispatchAction({type: 'legendToggleSelect',name: params.name})
}const initChart = () => {const lineOption = {title: {text: _data.line.title},tooltip: {trigger: 'axis'},legend: {show: false},grid: {left: '3%',right: '4%',bottom: '3%',containLabel: true},xAxis: {type: 'category',boundaryGap: false,data: _data.line.categories},yAxis: {type: 'value'},series: _data.line.series}const pieOption = {title: {text: _data.pie.title},tooltip: {trigger: 'item',formatter: '{a} <br/>{b} : {c} ({d}%)'},legend: {show: false},series: [{name: '访问来源',type: 'pie',radius: '55%',center: ['50%', '60%'],data: _data.pie.series,itemStyle: {emphasis: {shadowBlur: 10,shadowOffsetX: 0,shadowColor: 'rgba(0, 0, 0, 0.5)'}}}]}const lineChartDom = lineChart.valueconst pieChartDom = pieChart.valueconst lineChartInstance = echarts.init(lineChartDom)const pieChartInstance = echarts.init(pieChartDom)lineChartInstance.setOption(lineOption)pieChartInstance.setOption(pieOption)chartInstance1.value = lineChartInstancechartInstance2.value = pieChartInstance
}onMounted(() => {initChart()
})
</script><style lang="scss" scoped>
.container {display: flex;width: 1200px;justify-content: space-between;margin-top: 20px;position: relative;.chart {width: 49%;height: 400px;}.legend1 {position: absolute;bottom: -50px;left: 50px;}.legend2 {position: absolute;bottom: -50px;right: 50px;}
}
</style>

效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/916556.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/916556.shtml
英文地址,请注明出处:http://en.pswp.cn/news/916556.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【2025年7月25日】TrollStore巨魔商店恢复在线安装

就在今日7月25日&#xff0c;TrollStore的在线安装功能再次变得可用&#xff0c;这对于许多iPhone用户来说无疑是个喜讯。在经历了近三个月的中断后&#xff0c;巨魔商店的企业证书意外的到来了&#xff0c;使得用户能够重新采用在线安装的方式&#xff01; 在线安装地址在文…

【05】C#入门到精通——C# 面向对象、类、静态变量static、类与类之间的调用

文章目录1 引入例子2 创建类2.1 类的访问属性2.2 英雄 特点类2.3 英雄信息打印3 静态变量static4 类 调用 类4.1 非静态 成员函数4.2 静态 成员函数1 引入例子 比如游戏中 描述英雄的角色&#xff0c; 我们可以像下面这样&#xff0c;给每一个英雄特点及拥有技能分别定义变量…

单片机的硬件结构

单片机的硬件结构 一、课程导入 在上一节课《认识单片机》中&#xff0c;我们知道单片机就像一个超级迷你的工厂&#xff0c;有着类似工厂的各个组成部分。而这个 “迷你工厂” 能正常运转&#xff0c;离不开其内部严谨的硬件结构。就像一座大厦&#xff0c;只有基础结构稳固且…

multiprocessing模块使用方法(二)

spawn_main是Python multiprocessing模块的核心内部函数&#xff0c;用于实现spawn启动方法的子进程初始化。以下结合代码Demo详细说明其使用方法和推荐场景。一、spawn_main的功能与定位核心作用&#xff1a; 在spawn模式下启动子进程&#xff0c;负责进程间通信管道的建立和资…

编程与数学 03-002 计算机网络 07_路由算法

编程与数学 03-002 计算机网络 07_路由算法一、静态路由算法&#xff08;一&#xff09;手工配置路由表的方法&#xff08;二&#xff09;静态路由的优缺点二、动态路由算法原理&#xff08;一&#xff09;距离矢量算法&#xff08;如贝尔曼 - 福特算法&#xff09;&#xff08…

使用Python,OpenCV计算跑图的图像彩色度

使用Python&#xff0c;OpenCV计算跑图的图像彩色度 这篇博客将介绍如何计算跑图里最鲜艳的top25图片和最灰暗的top25图片并显示色彩彩色度值展示。 效果图 以下分别是最鲜艳top25和最灰暗top25对比效果图&#xff1a; 最鲜艳top25效果图&#xff1a; 最灰暗top25效果图…

LeetCode 60:排列序列

LeetCode 60&#xff1a;排列序列问题定义与核心挑战 给定整数 n 和 k&#xff0c;返回集合 {1,2,...,n} 的第 k 个字典序排列。直接生成所有排列再遍历到第 k 个的方法&#xff08;时间复杂度 O(n!)&#xff09;会因 n≥10 时阶乘爆炸而超时&#xff0c;因此需要 数学推导 贪…

亚远景-传统功能安全VS AI安全:ISO 8800填补的标准空白与实施难点

一、为什么需要ISO 8800&#xff1a;传统安全标准的“盲区”传统功能安全&#xff08;ISO 26262&#xff09;• 假设&#xff1a;系统行为可被完整规格化&#xff0c;失效模式可枚举&#xff0c;风险可用概率-危害矩阵量化。• 盲区&#xff1a;对“设计意图正确&#xff0c;但…

菜鸟教程 R语言基础运算 注释 和数据类型

菜鸟教程 R语言基础运算 注释 和数据类型 1.注释 注释主要用于一段代码的解析&#xff0c;可以让阅读者更易理解&#xff0c;编程语言的注释会被编译器忽略掉&#xff0c;且不会影响代码的执行。 一般编程语言的注释分为单行注释与多行注释&#xff0c;但是 R 语言只支持单行注…

华为云ELB(弹性负载均衡)持续报异常

华为云ELB&#xff08;弹性负载均衡&#xff09;持续报异常&#xff0c;需结合实例类型&#xff08;共享型/独享型&#xff09;和异常代码进行针对性排查。以下是分步排查建议&#xff1a;一、根据实例类型排查网络配置共享型实例 安全组规则&#xff1a;检查后端服务器安全组是…

《R for Data Science (2e)》免费中文翻译 (第2章) --- Workflow: basics

写在前面 本系列推文为《R for Data Science (2)》的中文翻译版本。所有内容都通过开源免费的方式上传至Github&#xff0c;欢迎大家参与贡献&#xff0c;详细信息见&#xff1a; Books-zh-cn 项目介绍&#xff1a; Books-zh-cn&#xff1a;开源免费的中文书籍社区 r4ds-zh-cn …

开源深度学习新宠:Burn框架助您无忧高效建模

在日新月异的人工智能世界里&#xff0c;各类深度学习框架如雨后春笋般涌现&#xff0c;而Burn&#xff0c;作为新一代的深度学习框架&#xff0c;以其不妥协的灵活性、高效性和可移植性崭露头角。本文将深入探讨Burn的核心功能、应用场景及具体使用方法&#xff0c;帮助您更好…

基于深度学习的图像分割:使用DeepLabv3实现高效分割

前言 图像分割是计算机视觉领域中的一个重要任务&#xff0c;其目标是将图像中的每个像素分配到不同的类别中。近年来&#xff0c;深度学习技术&#xff0c;尤其是卷积神经网络&#xff08;CNN&#xff09;&#xff0c;在图像分割任务中取得了显著的进展。DeepLabv3是一种高效的…

如何高效合并音视频文件(时间短消耗资源少)(二)

英语字幕 1 00:00:06,480 --> 00:00:08,400 Good morning. We have a banger for you2 00:00:08,400 --> 00:00:09,840 today. We&amp;#39;re going to launch chatbt3 00:00:09,840 --> 00:00:11,519 agent. But before jumping into that, I&amp;#39;d4 00…

内网后渗透攻击过程(实验环境)--4、权限维持(2)

用途限制声明&#xff0c;本文仅用于网络安全技术研究、教育与知识分享。文中涉及的渗透测试方法与工具&#xff0c;严禁用于未经授权的网络攻击、数据窃取或任何违法活动。任何因不当使用本文内容导致的法律后果&#xff0c;作者及发布平台不承担任何责任。渗透测试涉及复杂技…

CentOS 9 配置国内 YUM 源

1.备份 sudo mv /etc/yum.repos.d/centos.repo /etc/yum.repos.d/centos.repo.backup sudo mv /etc/yum.repos.d/centos-addons.repo /etc/yum.repos.d/centos-addons.repo.backup2.创建新文件 vi /etc/yum.repos.d/centos.repo[baseos] nameCentOS Stream $releasever - BaseO…

【算法】递归、搜索与回溯算法入门

文章目录递归什么是递归为什么会用到递归如何理解递归如何写好一个递归搜索 vs 深度优先遍历 vs 深度优先搜索 vs 宽度&#xff08;广度&#xff09;优先遍历 vs 宽度&#xff08;广度&#xff09;优先搜索 vs 暴搜深度优先遍历 vs 深度优先搜索&#xff08;dfs&#xff09;宽度…

借助Aspose.HTML控件,在 Python 中将 SVG 转换为 PDF

您可能会发现许多解决方案都提供以编程方式将SVG转换为PDF 的功能。但这篇博文将介绍一个功能强大的 SDK&#xff0c;供 Python 开发人员自动化文件转换和操作。本指南将重点介绍通过 .NET 实现 Python 的 Aspose.HTML。此外&#xff0c;我们将逐步讲解相关步骤和代码片段&…

高级06-Java网络编程:从Socket到HTTP

引言&#xff1a;Java 网络编程的重要性 随着互联网技术的飞速发展&#xff0c;网络编程已成为现代软件开发中不可或缺的一部分。Java 作为一种广泛应用于企业级开发和分布式系统的编程语言&#xff0c;提供了强大的网络通信支持。从底层的 Socket 编程到高层的 HTTP 协议处理&…

STM32的蓝牙通讯(HAL库)

蓝牙基础知识&#xff08;了解即可&#xff09;&#xff1a;1.是一种利用低功率无线电&#xff0c;支持设备短距离通信的无线电技术&#xff0c;能在包括移动电话、PDAQ、无线耳机、笔记本电脑、相关外设等众多设备之间进行无线信息交换&#xff0c;蓝牙工作在全球通用的2.4 GH…