vue左侧漏斗切换 echart图表动态更新

这个需求是根据点击左侧的箭头部分,右侧图表切换,左侧选中数据高亮(图片用的svg)

一、效果图

 

 二、vue组件

<template><div class="funnel_wrap"><div class="flex_between"><div class="sec_title">测试</div><!-- <el-checkbox label="平均值" v-model="averageCheck"  @change="changeAverage"></el-checkbox> --></div><div class="flex_center funnel_con" v-if="flowList.items&&flowList.items.length>0"><div class="flow_con"><div class="left_position pointer"><svg-icon icon-class="arrow" :style="`color:${chooseId==5||chooseId==6||chooseId==7?'green':'#DFE1EB'};position:absolute;right:0;bottom:-3px;width: 6px;height: 6px;`"></svg-icon><div @click="changeFunnel(7)" :class="['left_top',chooseId==7?'leftactive':'']"><div class="left_title">{{radioList[6]}}%</div></div><div @click="changeFunnel(6)" :class="['left_cen',chooseId==6?'leftactive':'']"  :style="`${chooseId==7?'border-bottom:0':''}`"><div class="left_title">{{radioList[5]}}%</div></div><div @click="changeFunnel(5)" :class="['left_bot',chooseId==5?'leftactive':'']" :style="`${chooseId==7||chooseId==6?'border-bottom:0':''}`"><div class="left_title">{{radioList[4]}}%</div></div></div><div :class="['flow_item',chooseList.includes(item.id)?'active':''] " :style="'width:'+(255-(12*index))+'px'" v-for="(item,index) in flowList.items" :key="index"><div class="item_lef">{{item.title}}</div><div class="item_rig" >{{item.newValue}}<div class="funnle"></div></div><div class="svg_box" v-if="index!==4" :style="`color:${chooseId==index?'green':'#DFE1EB'};right:-${(15+12*index)}px`" ><svg-icon @click="changeFunnel(index)" class="pointer" :style="'height:42px;width:'+(26+index*12)+'px'" :icon-class="'funnel'+index"></svg-icon><div class="title"  :style="`left:${(30+index*12)}px;color:${chooseId==index?'green':'#212848'}`">{{radioList[index]}}%</div></div></div></div><div class="flow_echart"><line-vue v-if="lineOpt.id" :opt="lineOpt" :heightNum="300"></line-vue></div></div><div v-else class="none">暂无数据</div></div>
</template><script>
import { defineComponent, onMounted, computed,reactive,ref } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { roomflow } from "@/api/analyze/index.js";
import lineVue from "@/components/echartsChange/lineVue.vue";
import { thousandthis, valueTransfer,processingData,$formatTime,millionTransfer } from "@/utils/utils";
export default defineComponent({components:{lineVue},props: {opt: {type: Object,default: () => {return {roomId:'',userId:''};},},optIds: {type: Object,default: () => {return {lineId: "funnel_data_id", // echarts图表默认id 同一个页面多次引用当前组件 id不能相同};},},},setup(props,context) {const router = useRouter(),route = useRoute()let averageCheck=ref(false)//平均值flagconst industryAvg=ref('')//平均值const formatTime=$formatTimeconst lineOpt = ref({});const chooseList=ref([0,1])//选中idconst chooseListArr=ref([])//选中趋势图const flowList=ref([])//漏斗列表const trendList=ref([])//曲线图列表const chooseId=ref('0')let radioList=ref([])//占比let colors = ["#4CAF50","#556FFD","#91CC75","#EA8533","#283E81","#097C38","#48D9D9","#93BEFF",];let renderColors = colors;const initData = (res,arrline) => {let data = res;if (data && data.length > 0) {let xList = [];let seriesList = [];let maxArr=[]data.forEach((element, index) => {element.points=element.points||[]maxArr.push(element.points.length)let arrnew=[]// if(element.points.length>0){arrnew = element.points.map((obj) => {return obj.value;}).join(",").split(",");// }     seriesList.push({name: element.title,type: "line",showSymbol: false,symbolSize: 6,seriesLayoutBy: "row",emphasis: { focus: "series" },data: [...arrnew],markLine : {symbol: ['none'],data : arrline?arrline:[],emphasis: {lineStyle: {width: 1,	// hover时的折线宽度}},},lineStyle: {width: 1,},         });});let max=Math.max(...maxArr)let maxIndex=maxArr.map(item => item).indexOf(max)xList = data[maxIndex].points.map((item) => {return formatTime(item.date,'HH:mm');});lineOpt.value = {id: props.optIds.lineId,resize:true,options: {color: renderColors,title: {text: "",},legend: {icon: "circle",// selectedMode:'single',itemHeight: 6,itemWidth: 6,left: "0px",itemGap: 24,// top:'bottom',textStyle: {//图例文字的样式color: "#596076",fontSize: 14,padding: [0, 0, 0, 0], //文字与图形之间的左右间距},// data: ["签约汇总", "计划招募", "计划孵化"],},tooltip: {// 鼠标移入的展示trigger: "axis",// axisPointer: {//   type: "cross",//   label: {//     backgroundColor: "#6a7985",//   },// },formatter: function (params) {let res = params[0].name+'分析数据\n';for (let i = 0; i < params.length; i++) {res += `<div style="margin-top: 4px;font-size: 14px;line-height: 22px;color: #596076;">${params[i].marker} ${params[i].seriesName}:${thousandthis(params[i].data)}</div>`;}return res;},backgroundColor: "rgba(255,255,255,.9)",borderColor: "#E2E6F5",borderWidth: 1,padding: [12, 16, 16, 16],},grid: {// 图表距离容器的距离left: "1%",right: '4%',bottom: "3%",top:'22%',containLabel: true, // 是否显示刻度,默认不显示},xAxis: [{type: "category",boundaryGap: false,axisLabel: {color: "#9095A7",fontSize: 12,margin: 13,},axisLine: {lineStyle: {color: "#DFE1EB",},},axisTick: {show: false,},data: xList,},],yAxis: [{type: "value",// min: 0,// max: function (value) {//   return value.max < 400 ? 400 : value.max;// },// interval: 1000,// splitNumber: 4,axisLabel: {color: "#9095A7",formatter(v) {return valueTransfer(Math.abs(v), 0, "w", true);},},splitLine: {lineStyle: {type: "dashed", //虚线},},},],series: seriesList,},};}};//格式化选中线条const initChoosrArr=(arrList)=>{let arr=[]chooseList.value.forEach((ele)=>{arr.push(arrList[ele])})return arr}//获取漏斗列表const getList = () => {let param = {userId:props.opt.userId,roomId: props.opt.roomId,};// roomflow(param).then((res) => { let res=    {"code": 200,"msg": "ok","data": {"flowRank": {"name": "flowRank","title": "测试数据","items": [{"title": "数据1","ratio": 1.0,"value": 2833543},{"title": "数据2","ratio": 0.12883587790974055,"value": 365062},{"title": "数据3","ratio": 0.85563822035709,"value": 312361},{"title": "数据4","ratio": 0.09972755881816232,"value": 31151},{"title": "数据5","ratio": 0.016532374562614364,"value": 515}],},"trends": [{"title": "数据1","points": [{"value": 30000,"date": "2023-07-02 09:25:00"},{"value": 35000,"date": "2023-07-02 09:30:00"},{"value": 50000,"date": "2023-07-02 09:35:00"},{"value": 100000,"date": "2023-07-02 09:40:00"},{"value": 130003,"date": "2023-07-02 09:45:00"},{"value": 190000,"date": "2023-07-02 09:50:00"},{"value": 230000,"date": "2023-07-02 09:55:00"},{"value": 250000,"date": "2023-07-02 10:00:00"},]},{"title": "数据2","points": [{"value": 6000,"date": "2023-07-02 09:25:00"},{"value": 7000,"date": "2023-07-02 09:30:00"},{"value": 8000,"date": "2023-07-02 09:35:00"},{"value": 9000,"date": "2023-07-02 09:40:00"},{"value": 10000,"date": "2023-07-02 09:45:00"},{"value": 11000,"date": "2023-07-02 09:50:00"},{"value": 12000,"date": "2023-07-02 09:55:00"},{"value": 21810,"date": "2023-07-02 10:00:00"},]},{"title": "数据3","points": [{"value": 4500,"date": "2023-07-02 09:25:00"},{"value": 4700,"date": "2023-07-02 09:30:00"},{"value": 10000,"date": "2023-07-02 09:35:00"},{"value": 10214,"date": "2023-07-02 09:40:00"},{"value": 12000,"date": "2023-07-02 09:45:00"},{"value": 13000,"date": "2023-07-02 09:50:00"},{"value": 14000,"date": "2023-07-02 09:55:00"},{"value": 15000,"date": "2023-07-02 10:00:00"},]},{"title": "数据4","points": [{"value": 400,"date": "2023-07-02 09:25:00"},{"value": 800,"date": "2023-07-02 09:30:00"},{"value": 1100,"date": "2023-07-02 09:35:00"},{"value": 1200,"date": "2023-07-02 09:40:00"},{"value": 1400,"date": "2023-07-02 09:45:00"},{"value": 1600,"date": "2023-07-02 09:50:00"},{"value": 1800,"date": "2023-07-02 09:55:00"},{"value": 2000,"date": "2023-07-02 10:00:00"},]},{"title": "数据5","points": [{"value": 0,"date": "2023-07-02 09:25:00"},{"value": 2,"date": "2023-07-02 09:30:00"},{"value": 13,"date": "2023-07-02 09:35:00"},{"value": 14,"date": "2023-07-02 09:40:00"},{"value": 34,"date": "2023-07-02 09:45:00"},{"value": 40,"date": "2023-07-02 09:50:00"},{"value": 53,"date": "2023-07-02 09:55:00"},{"value": 63,"date": "2023-07-02 10:00:00"},]}],"industryAvg": 100}
}if (res.data) {if(res.data.flowRank.items){radioList.value=[]//格式漏斗右侧返回占比res.data.flowRank.items.forEach((ele,index) => {ele.id=indexele.newValue=millionTransfer(ele.value)if(index!==0){radioList.value.push(processingData(ele.ratio*100,2))}});// 漏斗左侧百分比计算radioList.value.push(processingData((res.data.flowRank.items[4].value/res.data.flowRank.items[2].value)*100,2))radioList.value.push(processingData((res.data.flowRank.items[4].value/res.data.flowRank.items[1].value)*100,2))          radioList.value.push(processingData((res.data.flowRank.items[4].value/res.data.flowRank.items[0].value)*100,2))}//绘制图表if(res.data.trends){chooseListArr.value=initChoosrArr(res.data.trends)initData(chooseListArr.value)}flowList.value=res.data.flowRanktrendList.value=res.data.trendsindustryAvg.value=res.data.industryAvg}// });};//点击漏斗const changeFunnel=(val)=>{chooseId.value=val;if(val<5){chooseList.value=[val,val+1]}else if(val==5){chooseList.value=[2,4]}if(val==6){chooseList.value=[1,4]}if(val==7){chooseList.value=[0,4]}chooseListArr.value=initChoosrArr(trendList.value)// 先判断是否有平均线再重绘图表changeAverage(averageCheck.value)}//点击平均值 val=true有平均线const changeAverage=(val)=>{if(val){let arrline=[{symbol: "none",silent:false, //鼠标悬停事件 true没有,false有lineStyle:{ //警戒线的样式 ,虚实 颜色type:"dashed", //样式  ‘solid’和'dotted'color:"#E98433",width: 1   //宽度},label:{show:false,color:"#E98433",position:'middle',// padding: ['0', '0', '0',tableWidth.value],formatter: function (params) {let res = "";res += `${params.name}:${params.value}`;return res;},},name:'平均值',yAxis:industryAvg.value}]initData(chooseListArr.value,arrline)}else{initData(chooseListArr.value)}}watch(props,(newValue) => {console.log(newValue);if (newValue && newValue.opt && newValue.opt.roomId) {getList()}},{  deep: true });onMounted(()=>{// getList()})return {flowList,chooseList,changeFunnel,chooseId,radioList,trendList,lineOpt,averageCheck,changeAverage}}
})
</script><style scoped lang="scss">
.funnel_wrap{margin-top: 24px;padding: 24px;color: #212848;font-size: 14px;background-color: #fff;.sec_title{font-size: 18px;font-weight: 500;}.funnel_con{padding: 24px;}.flow_con{position: relative;padding-left: 100px;padding-right: 112px;.left_position{position: absolute;top: 30px;left:0;.left_top{width: 100px;height: 198px;color:#DFE1EB;border:1px solid #DFE1EB;border-right:0;}.left_cen{width: 72px;height: 146px;position:absolute;left:24px;bottom:-0.5px;color:#DFE1EB;border:1px solid #DFE1EB;border-right:0;}.left_bot{width: 25px;height: 92px;position:absolute;left:72px;color:#DFE1EB;bottom:0px;border:1px solid #DFE1EB;border-right:0;}.left_title{position: absolute;line-height: 20px;top: -24px;right: 0;       color: #212848;}.leftactive{border:1px solid green;border-right:0;color: green;.left_title{color: green;}}}.flow_item{background-color:#F8F9FB ;margin-bottom: 12px;height: 40px;line-height: 40px;display: flex;align-items: center;position: relative;.item_lef{width: 116px;text-align: center;box-sizing: border-box;}.item_rig{padding-left: 16px;position: relative;flex: 1;.funnle{position: absolute;border-bottom:40px solid #fff;border-left: 12px solid transparent;right: 0;top: 0;}}}.active{.item_lef{background-color: green;color: #fff;}.item_rig{background-color: #EEF1FF;}}.svg_box{position: absolute;top: 25px;right: -10px;.title{position: absolute;left:0;top: 0;}}}.flow_echart{flex: 1;}.none{margin-top: 12px;color: #9095A7;text-align: center;}
}
// .svg-icon {
//   height: 3em;
// }
</style>

三、utils.js方法

export function millionTransfer(value,digits = 4,unit = "w",decimal = 2,removeZero = false
) {// unit = unit || "w"const valueNum = Number(value)const transferNum = Math.pow(10, digits)if (!isNaN(valueNum)) {if (valueNum < transferNum && valueNum >= 0) {return value}const num = floatDivideMethod(valueNum, transferNum)if (removeZero) {return `${parseFloat(num.toFixed(decimal))}${unit}`}return `${num.toFixed(decimal)}${unit}`}return value
}export function thousandthis(num) {if (!num && num !== 0) return nullif (num === '--') return '--'if (!(!isNaN(Number(num)) && typeof Number(num) === 'number')) {return '0'}return (num || 0).toString().replace(/\d+/, function(n) {const len = n.lengthif (len % 3 === 0) {return n.replace(/(\d{3})/g, ',$1').slice(1)}return n.slice(0, len % 3) + n.slice(len % 3).replace(/(\d{3})/g, ',$1')})
}/* 最早的数据没有亿,只有万,兼容之前数据,后面转换万和亿的数据用这个方法 */
export function valueTransfer(value, decimal = 2, unit = "万", removeZero = false) {let outputVal = valueconst valueNum = Number(value)const transferNum1 = Math.pow(10, 4)const transferNum2 = Math.pow(10, 8)if (!isNaN(valueNum)) {if (valueNum < transferNum1) {outputVal = value} else if (valueNum >= transferNum1 && valueNum < transferNum2) {outputVal = millionTransfer(value, 4, unit, decimal, removeZero)} else {outputVal = millionTransfer(value, 8, "亿", decimal, removeZero)}}return outputVal
}//保留两位小数
export function processingData(data,length){data=Number(data);data=Number((parseInt(data * 100) / 100).toFixed((length!=undefined?length:2)))data=data+''return data
}import moment from "moment"
export function $formatTime (time, format = "YYYY-MM-DD HH:mm:ss") {if (time && time !== "--") {if (format === "timestamp") {return Number(moment(time).utcOffset(8).format("x"))}return moment(time).format(format)}return time
}

四、父组件调用

import flowFunnel from "./components/flowFunnel.vue";components:{flowFunnel,},

 

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

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

相关文章

[机器学习]分类算法系列①:初识概念

目录 1、概念 2、数据集介绍与划分 2.1、数据集的划分 2.2、sklearn数据集介绍 2.2.1、API 2.2.2、分类和回归数据集 分类数据集 回归数据集 返回类型 3、sklearn转换器和估计器 3.1、转换器 三种方法的区别 3.2、估计器 3.2.1、简介 3.2.2、API 3.3、工作流程 …

热门框架漏洞

文章目录 一、Thinkphp5.0.23 代码执行1.thinkphp5框架2.thinkphp5高危漏洞3.漏洞特征4.THinkphp5.0 远程代码执行--poc5.TP5实验一(Windows5.0.20)a.搭建实验环境b.测试phpinfoc.写入shelld.使用菜刀连接 6.TP5实验二(Linux5.0.23)a.搭建实验环境b.测试方法c.测试phpinfod.写入…

小程序快速备案助手代备案小程序开发

小程序快速备案助手代备案小程序开发 用户注册与登录&#xff1a;用户可以通过手机号或其他方式进行注册和登录&#xff0c;以便进行备案相关操作。备案信息填写&#xff1a;用户可以填写小程序的备案信息&#xff0c;包括小程序名称、小程序服务类目、域名等。备案材料上传&a…

ODC现已开源:与开发者共创企业级的数据库协同开发工具

OceanBase 开发者中心&#xff08;OceanBase Developer Center&#xff0c;以下简称 ODC&#xff09;是一款开源的数据库开发和数据库管理协同工具&#xff0c;从首个版本上线距今已经发展了三年有余&#xff0c;ODC 逐步由一款专为 OceanBase 打造的开发者工具演进成为支持多数…

香橙派Orangepi Zero2 刷机步骤

目录 1.香橙派Orangepi Zero2简介 2.刷机 2.1物料准备 2.2 格式化SD卡 2.3 烧录镜像到SD卡 2.4 安装SD卡到Orangepi 2.5 连接Pi电源 2.6 MobaXterm 串口登陆Orangepi 2.6.1 连线示意图 2.6.2 MobaXterm 使用 2.6.3修改登陆密码 2.6.4 网络配置 2.7 SSH登陆开发版…

14 mysql bit/json/enum/set 的数据存储

前言 这里主要是 由于之前的一个 datetime 存储的时间 导致的问题的衍生出来的探究 探究的主要内容为 int 类类型的存储, 浮点类类型的存储, char 类类型的存储, blob 类类型的存储, enum/json/set/bit 类类型的存储 本文主要 的相关内容是 bit/json/enum/set 类类型的相关…

中心差分法-学习笔记《结构动力学-陈政清》

激励分段解析法仅仅对外载荷进行了离散&#xff0c;但对运动方程还是严格满足的&#xff0c;体系的运动在时间轴上依然是满足运动微分方程。然而&#xff0c;一般的时域逐步积分法进一步放松要求&#xff0c;不仅仅对外荷载进行离散化处理&#xff0c;也对体系的运动进行离散化…

c++入门一

参考&#xff1a;https://www.learncpp.com/cpp-tutorial/ When you finish, you will not only know how to program in C, you will know how NOT to program in C, which is arguably as important. Tired or unhappy programmers make mistakes, and debugging code tends…

Swift 如何从图片数据(Data)检测原图片类型?

功能需求 如果我们之前把图片对应的数据(Data)保持在内存或数据库中,那么怎么从 Data 对象检测出原来图片的类型呢? 如上图所示:我们将 11 张不同类型的图片转换为 Data 数据,然后从 Data 对象正确检测出了原图片类型。 目前,我们的代码可以检测出 jpeg(jpg), tiff,…

逻辑回归Logistic

回归 概念 假设现在有一些数据点&#xff0c;我们用一条直线对这些点进行拟合&#xff08;这条直线称为最佳拟合直线&#xff09;&#xff0c;这个拟合的过程就叫做回归。进而可以得到对这些点的拟合直线方程。 最后结果用sigmoid函数输出 因此&#xff0c;为了实现 Logisti…

K8S自动化运维容器化(Docker)集群程序

K8S自动化运维容器化集群程序 一、K8S概述1.什么是K8S2.为什么要用K8S3.作用及功能 二、K8S的特性1.弹性伸缩2.自我修复3.服务发现和负载均衡4.自动发布和回滚5.集中化配置管理和秘钥管理6.存储编排7.任务批量处理运行 三、K8S的集群架构1.架构2.模式3.工作4.流程图 四、K8S的核…

如何解决vue3.0+typescript项目提示找不到模块“./App.vue

一、解决方案如下&#xff1a;需在项目目录下加上下面这段代码即可&#xff01;如果没有vite-env.d.ts目录需要继续往下看 declare module *.vue {import type { DefineComponent } from vueconst vueComponent: DefineComponent<{}, {}, any>export default vueCompon…

TBOX开发需求说明

TBOX功能需求&#xff1a; 支持4G上网功能&#xff0c;可获取外网IP&#xff0c;可和云端平台连通支持路由功能&#xff0c;支持计算平台、网关和云端平台建立网络连接支持USB转网口&#xff0c;智能座舱会通过USB连接AG35建立网络连接&#xff08;类似IVI通过USB口连接TBOX&a…

前端面试中Vue的有经典面试题二

7. Vue中给data中的对象属性添加一个新的属性时会发生什么&#xff0c;如何解决&#xff1f; 示例&#xff1a; 点击button会发现&#xff0c; obj.b 已经成功添加&#xff0c;但是视图并未刷新&#xff1a; 原因在于在Vue实例创建时&#xff0c; obj.b 并未声明&#xff0c;因…

SQL求解用户连续登录天数

数据分析面试过程中&#xff0c;一般都逃不掉对SQL的考察&#xff0c;可能是笔试的形式&#xff0c;也可能是面试过程中面试官当场提问&#xff0c;当场在纸上写出&#xff0c;或者简单说一下逻辑。 今天&#xff0c;就来分享一道面试中常常被问到的一类SQL问题&#xff1a;连…

推荐个一行代码的Python可视化神器

学过Python数据分析的朋友都知道&#xff0c;在可视化的工具中&#xff0c;有很多优秀的三方库&#xff0c;比如matplotlib&#xff0c;seaborn&#xff0c;plotly&#xff0c;Boken&#xff0c;pyecharts等等。这些可视化库都有自己的特点&#xff0c;在实际应用中也广为大家使…

在springboot中配置mybatis(mybatis-plus)mapper.xml扫描路径的问题

我曾经遇到过类似问题&#xff1a; mybatis-plus的mapper.xml在src/main/java路径下如何配置pom.xml和application.yml_idea 把mapper文件放到java下如何配置_梓沂的博客-CSDN博客 当时只是找到解决问题的办法&#xff0c;但对mybatis配置来龙去脉并未深入了解&#xff0c;所…

操作系统备考学习 day1 (1.1.1-1.3.1)

操作系统备考学习 day1 计算机系统概述操作系统的基本概念操作系统的概念、功能和目标操作系统的四个特征并发共享虚拟异步 操作系统的发展和分类操作系统的运行环境操作系统的运行机制 年初做了一个c的webserver 的项目&#xff0c;在学习过程中已经解除部分操作系统的知识&am…

解决Debian系统通过cifs挂载smb后,中文目录乱码问题

解决Debian系统通过cifs挂载smb后&#xff0c;中文目录乱码问题 //$smb_server/share /mnt/nas_share cifs credentials/root/.smbcredentials,iocharsetutf8 0 0默认通过以上命令挂载smb&#xff0c;但是在查看文件目录时&#xff0c;中文乱码 解决问题方式&#xff1a; de…

C语言——指针基本语法

概述 内存地址 在计算机内存中&#xff0c;每个存储单元都有一个唯一的地址(内存编号)。 通俗理解&#xff0c;内存就是房间&#xff0c;地址就是门牌号 指针和指针变量 指针&#xff08;Pointer&#xff09;是一种特殊的变量类型&#xff0c;它用于存储内存地址。 指针的实…