金子塔图,自定义图表,伪漏斗图

金子塔图,自定义图表,伪漏斗图

简易的金字塔图,设置不太灵活,可供使用者参考,需要使用者根据页面的需求复杂度等再做修改。

另附链接地址:https://www.isqqw.com/pcenter?userid=6427

// 原始数据
let data = [
   { name: '测试数据', value: 4 },
   { name: '测试原理', value: 2 },
   { name: '测试功能', value: 8 },
]
// 将数据根据从小到大排序
let newdata = sortObject(data);
// 图例数据
let lengthData = [];
// 返回数据
let resultData = data.map((item, index) => {
   let graw = item.value > 9 ? 78 : 83;
   lengthData.push({
      type: 'group',
      top: index * 25,
      scale: [1, 1],
      children: [
         {
            type: 'circle',
            shape: {
               cx: 0,
               cy: 7,
               r: 5
            },
            style: {
               fill:
                  index === 0 ? '#07a9ab' : index === 1 ? '#008CD2' : '#0847e7'
            }
         },
         {
            type: 'text',
            style: {
               text: item.name,
               fill: '#fff',
               fontSize: 14,
               x: 10,
               y: 2
            }
         },
         {
            type: 'text',
            name: item.name,
            style: {
               text: item.value,
               fill: '#fff',
               fontSize: 17,
               x: 70,
               y: 0
            }
         },
         {
            type: 'text',
            style: {
               text: '个',
               fill: '#fff',
               fontSize: 14,
               x: graw,
               y: 2
            }
         }
      ]
   });
   if (index === 0) {
      return {
         style: {
            fill: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
               { offset: 0, color: '#07a9ab' },
               { offset: 1, color: '#09fffb' }
            ])
         },
         ...item
      };
   } else if (index === 1) {
      return {
         style: {
            fill: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
               { offset: 0, color: '#025279' },
               { offset: 1, color: '#16a7ef' }
            ])
         },
         ...item
      };
   } else {
      return {
         style: {
            fill: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
               { offset: 0, color: '#0332a9' },
               { offset: 1, color: '#0847e7' }
            ])
         },
         ...item
      };
   }
});
// 获取计算的数据
let getData = pyramidChart(
   resultData,
   document.getElementById('container')
);
option = {
   backgroundColor: '#022c32',
   graphic: [
      {
         type: 'group',
         left: '5%',
         top: 'center',
         scale: [1, 1],
         onclick: function (params) {

         },
         children: getData
      },
      {
         type: 'group',
         left: '55%',
         top: 'center',
         scale: [1, 1],
         onclick: function (params) {

         },
         children: lengthData
      }
   ],
   series: []
};
// 排序
function sortObject(arr) {
   return arr.sort(function (a, b) {
      return a['value'] - b['value'];
   });
}
// 数据处理
function pyramidChart(data = [], dom, option = {}) {
   let domHeight = dom ? dom.clientHeight : 0;
   let domWidth = dom ? dom.clientWidth : 0;
   // 默认获取一个正方形空间
   let maxDistance = domHeight > domWidth / 2 ? domWidth / 2 : domHeight;
   // 合并设置
   let resultOption = Object.assign(
      {
         slanted: 1, // 每层底部的倾斜度
         maxWidth: maxDistance, // 金字塔最大宽度
         maxHeight: maxDistance, // 金字塔最大高度
         offset: 35 //偏差
      },
      option
   );
   if (data.length === 1) {
      resultOption.slanted = 50;
   }
   if (data.length === 2) {
      resultOption.slanted = 25;
   }
   if (data.length === 3) {
      resultOption.slanted = 10;
   }
   // 减去多余的误差边距
   resultOption.maxHeight = resultOption.maxHeight - resultOption.offset;
   // 一半最大宽度,用于计算左右边距
   let halfMaxWidth = resultOption.maxWidth / 2;
   // 数据最终
   let resultData = [];
   // 数据值 数组
   let dataNums = data.map(item => item.value || 0);
   // 计算数据总和
   let dataNumSum =
      dataNums.length > 0 &&
      dataNums.reduce(function (prev, curr) {
         return Number(prev || 0) + Number(curr || 0);
      });
   // 中间数据点坐标数组 根据长度比值算出
   let midlinePoint = [];
   let multipleLayer = [0.6];
   // 计算倍数等基础数据
   dataNums.forEach((item, index, arr) => {
      let itemNext = arr[index + 1];
      if (itemNext) {
         multipleLayer.push(itemNext / dataNums[0]); // 计算倍数
      }
      // 计算点坐标 长度
      let point =
         Math.round((item / dataNumSum) * resultOption.maxHeight * 1000) / 1000;
      midlinePoint.push(point);
   });
   // 三角形的高度
   let triangleHeight = 0;
   let triangleHeightLayer = [];
   // 三角形tan角度
   let triangleRatio = halfMaxWidth / resultOption.maxHeight;
   midlinePoint.forEach(item => {
      triangleHeight = triangleHeight + item;
      triangleHeightLayer.push(triangleHeight);
   });
   // 中间数据点 最后的数据长度
   let midlinePointFinally =
      triangleHeightLayer[triangleHeightLayer.length - 1] || 0;
   // 开始拼接数据
   data.forEach((item, index) => {
      let arrObj = [];
      let triangleHeightLayerOne = triangleHeightLayer[index];
      let triangleHeightLayerOneLast = triangleHeightLayer[index - 1] || 0;
      let multipleLayerOne = multipleLayer[index];
      let multipleLayerOneLast = multipleLayer[index - 1] || 0;
      // 第一层数据单独处理
      if (index === 0) {
         arrObj.push(
            [0, 0],
            [
               -triangleRatio *
               (triangleHeightLayerOne - resultOption.slanted * multipleLayerOne),
               triangleHeightLayerOne - resultOption.slanted * multipleLayerOne
            ],
            [0, triangleHeightLayerOne],
            [
               triangleRatio *
               (triangleHeightLayerOne - resultOption.slanted * multipleLayerOne),
               triangleHeightLayerOne - resultOption.slanted * multipleLayerOne
            ]
         );
      } else {
         arrObj.push(
            [0, triangleHeightLayerOneLast],
            [
               -triangleRatio *
               (triangleHeightLayerOneLast -
                  resultOption.slanted * multipleLayerOneLast),
               triangleHeightLayerOneLast -
               resultOption.slanted * multipleLayerOneLast
            ],
            [
               -triangleRatio *
               (triangleHeightLayerOne - resultOption.slanted * multipleLayerOne),
               triangleHeightLayerOne - resultOption.slanted * multipleLayerOne
            ],
            [0, triangleHeightLayerOne],
            [
               triangleRatio *
               (triangleHeightLayerOne - resultOption.slanted * multipleLayerOne),
               triangleHeightLayerOne - resultOption.slanted * multipleLayerOne
            ],
            [
               triangleRatio *
               (triangleHeightLayerOneLast -
                  resultOption.slanted * multipleLayerOneLast),
               triangleHeightLayerOneLast -
               resultOption.slanted * multipleLayerOneLast
            ]
         );
      }
      resultData.push({
         type: 'polygon',
         z: 1,
         shape: {
            points: arrObj
         },
         name: item.name,
         style: item.style
      });
   });
   // 添加线
   resultData.push({
      type: 'polyline',
      shape: {
         points: [
            [0, 0],
            [0, midlinePointFinally]
         ]
      },
      style: {
         stroke: '#f2f2f2',
         opacity: 0.2,
         lineWidth: 1
      },
      z: 2
   });
   // 返回
   return resultData;
};

  

 

posted @ 2023-01-10 10:48  星涑  阅读(226)  评论(0编辑  收藏  举报