Vue封装的标准漏斗图教程

 更新时间:2025年02月12日 15:37:17   作者:努力奋斗小白  
文章展示了基于Vue封装的标准漏斗图的代码,包括权重算法、滚轮监听和点击示例功能,旨在提供实用的图表展示技巧

Vue封装的标准漏斗图

代码展示

基于Vue封装的标准漏斗图,增加权重算法,避免数值很小时图表显示过小,监听滚轮高度,防止弹窗飞走,点击示例动态显示对应的梯形图表块。

/**
 * 权重
 */
export function qz(arr) {
  // 计算数列的总和
  const total = arr.reduce((sum, val) => sum + val, 0)
  // 如果总和为零,则无法平衡,直接返回原数组
  if (total === 0) {
    return arr
  }
  function nonlinearScale(val) {
    return Math.sqrt(val) // 对数值进行平方根变换
  }
  // 平方根为了让数小点,一般降级都采用平方根处理
  const scaledArr = arr.map(val => nonlinearScale(val))
  // 计算缩放后数列的总和
  const scaledTotal = scaledArr.reduce((sum, val) => sum + val, 0)
  // 将缩放后的数列归一到100%,超过100就越界了
  let balancedArr = scaledArr.map(val => (val / scaledTotal) * 100)
  // 由于浮点数的精度问题,总和可能不是精确的100%,问题不大
  const error = 100 - balancedArr.reduce((sum, val) => sum + val, 0)
  const nonZeroCount = balancedArr.filter(val => val > 0).length
  if (nonZeroCount > 0) {
    const adjustment = error / nonZeroCount
    balancedArr = balancedArr.map(val => val + (val > 0 ? adjustment : 0))
  }
  // 四舍五入到小数点后两
  balancedArr = balancedArr.map(val => Math.round(val * 100) / 100)
  return balancedArr
}
  <LdChart :chart-data="charDataArray" :flag-type="flagType" />

// 接口返回
this.charDataArray = []
          this.charDataTwoArray = []
          this.num1 = 0
          this.num2 = 0
          if (res.data && res.data.length > 0) {
            this.loading = false
            // 数据都是固定的五个!!!1
            const obj1 = [
              { height: '20%', top: '0%', name: '名称1', value: '', type: '10%', unit: '万元', color: '#7aa5fa', checkItem: false, itemColor: '#7aa5fa', fontColor: '#303313' },
              { height: '20%', top: '20%', name: '名称2', value: '', type: '30%', unit: '万元', color: '#7ae0b8', checkItem: false, itemColor: '#7ae0b8', fontColor: '#303313' },
              { height: '20%', top: '40%', name: '名称3', value: '', type: '50%', unit: '万元', color: '#f6e0b4', checkItem: false, itemColor: '#f6e0b4', fontColor: '#303313' },
              { height: '20%', top: '60%', name: '名称4', value: '', type: '80%', unit: '万元', color: '#d9d9d9', checkItem: false, itemColor: '#d9d9d9', fontColor: '#303313' },
              { height: '20%', top: '80%', name: '名称5', value: '', type: '100%', unit: '万元', color: '#f5aa8a', checkItem: false, itemColor: '#f5aa8a', fontColor: '#303313' }
            ]
            const obj2 = [
              { height: '20%', top: '0%', name: '名称1', value: '', type: '10%', unit: '个', color: '#7aa5fa', checkItem: false, itemColor: '#7aa5fa', fontColor: '#303313' },
              { height: '20%', top: '20%', name: '名称2', value: '', type: '30%', unit: '个', color: '#7ae0b8', checkItem: false, itemColor: '#7ae0b8', fontColor: '#303313' },
              { height: '20%', top: '40%', name: '名称3', value: '', type: '50%', unit: '个', color: '#f6e0b4', checkItem: false, itemColor: '#f6e0b4', fontColor: '#303313' },
              { height: '20%', top: '60%', name: '名称4', value: '', type: '80%', unit: '个', color: '#d9d9d9', checkItem: false, itemColor: '#d9d9d9', fontColor: '#303313' },
              { height: '20%', top: '80%', name: '名称5', value: '', type: '100%', unit: '个', color: '#f5aa8a', checkItem: false, itemColor: '#f5aa8a', fontColor: '#303313' }
            ]
            const sumOne = res.data[0].reduce((sum, current) => sum + Number(current.sales), 0)
            const sumTwo = res.data[1].reduce((sum, current) => sum + Number(current.sales), 0)
            this.num1 = sumOne.toFixed(2)
            this.num2 = sumTwo
            obj1.forEach(item => {
              res.data[0].forEach(it => {
                if (item.type === it.winOrderRate) {
                  item.value = it.sales
                  // 计算比例
                  let bl = 0
                  sumOne === 0 ? bl = 0 : bl = Math.floor(Number(it.sales) / sumOne * 100)
                  Number(it.sales) > 0 && bl === 0 ? bl = 1 : ''
                  // 设置合适的比例1
                  item.height = bl + '%'
                }
              })
            })
            obj2.forEach(item => {
              res.data[1].forEach(it => {
                if (item.type === it.winOrderRate) {
                  item.value = it.sales
                  // 计算比例
                  let bl = 0
                  sumTwo === 0 ? bl = 0 : bl = Math.floor(Number(it.sales) / sumTwo * 100)
                  Number(it.sales) > 0 && bl === 0 ? bl = 1 : ''
                  // 设置合适的比例
                  item.height = bl + '%'
                }
              })
            })
            const qzOne = qz(obj1.map(it => Number(it.height.split('%')[0])))
            const qzTwo = qz(obj2.map(it => Number(it.height.split('%')[0])))
            obj1.forEach((it, index) => {
              it.height = qzOne[index] + '%'
            })
            obj2.forEach((it, index) => {
              it.height = qzTwo[index] + '%'
            })
            // 排除0的,
            const objNew1 = obj1.filter(item => item.value !== 0 && item.value !== '0')
            const objNew2 = obj2.filter(item => item.value !== 0 && item.value !== '0')
            // 第一个是 0, 第二个是 第一个的高度, 第三个是 第一个+ 第二个 第四个是 1+2+3
            const result = []
            const result1 = []
            let sum = 0
            let sum1 = 0
            for (let i = 0; i < objNew1.length; i++) {
              sum += Number(objNew1[i].height.split('%')[0])
              result.push(sum)
            }
            for (let i = 0; i < objNew2.length; i++) {
              sum1 += Number(objNew2[i].height.split('%')[0])
              result1.push(sum1)
            }
            result.pop()
            result1.pop()
            objNew1.forEach((it, index) => {
              // 第一个是 0, 之后的每一个都是 前面的相加!!!1
              if (index === 0) {
                it.top = '0%'
              } else {
                it.top = result[index - 1] + '%'
              }
            })
            objNew2.forEach((it, index) => {
              // 第一个是 0, 之后的每一个都是 前面的相加
              if (index === 0) {
                it.top = '0%'
              } else {
                it.top = result1[index - 1] + '%'
              }
            })
            // 计算比例得
            const one = '名称1'
            const two = '名称2'
            const three = '名称3'
            const four = '名称4'
            const five = '名称5'
            const all = [one, two, three, four, five]
            this.charDataArray.push(all)
            this.charDataArray.push(objNew1)
            this.charDataArray.push(objNew2)
            this.charDataArray.push('类型1')

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Vue学习笔记进阶篇之多元素及多组件过渡

    Vue学习笔记进阶篇之多元素及多组件过渡

    本篇文章主要介绍了Vue学习笔记进阶篇之多元素及多组件过渡,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-07-07
  • Ant Design Vue Pro静态路由如何改为动态路由

    Ant Design Vue Pro静态路由如何改为动态路由

    这篇文章主要介绍了Ant Design Vue Pro静态路由如何改为动态路由问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-10-10
  • vue 路由懒加载详情

    vue 路由懒加载详情

    这篇文章主要介绍了vue 路由懒加载,当打包构建应用时,JavaScript 包会变得非常大,影响页面加载,这便是vue 路由懒加载,接下来随小编一起进入文章了解更多详细内容吧
    2021-10-10
  • 三步搞定:Vue.js调用Android原生操作

    三步搞定:Vue.js调用Android原生操作

    这篇文章主要介绍了三步搞定:Vue.js调用Android原生操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • Nuxt的路由动画效果案例

    Nuxt的路由动画效果案例

    这篇文章主要介绍了Nuxt的路由动画效果案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • vue中使用rem布局代码详解

    vue中使用rem布局代码详解

    在本篇文章里小编给大家整理的是关于vue中使用rem布局代码详解知识点,需要的朋友们参考下。
    2019-10-10
  • 前端架构vue架构插槽slot使用教程

    前端架构vue架构插槽slot使用教程

    这篇文章主要为大家介绍了前端vue架构插槽slot使用教程示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-02-02
  • Vue使用ElementUI动态修改table单元格背景颜色或文本颜色

    Vue使用ElementUI动态修改table单元格背景颜色或文本颜色

    本文主要介绍了Vue使用ElementUI动态修改table单元格背景颜色或文本颜色,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • 前端实现Vue组件页面跳转的多种方式小结

    前端实现Vue组件页面跳转的多种方式小结

    这篇文章主要为大家详细介绍了前端实现Vue组件页面跳转的多种方式,文中的示例代码讲解详细,具有一定的参考价值,有需要的小伙伴可以了解下
    2024-02-02
  • vue中iframe使用以及结合postMessage实现跨域通信

    vue中iframe使用以及结合postMessage实现跨域通信

    这篇文章主要介绍了vue中iframe使用以及结合postMessage实现跨域通信方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09

最新评论