最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 前端高手系列-echarts桑基图运用

    正文概述 掘金(大辉小猿)   2020-12-18   870

    什么是桑吉图

    桑基图是一种展示数据流动的利器,先来了解一下它的概念

    再看一下在echars官网的实例

    前端高手系列-echarts桑基图运用

    对应的代码:

    option = {
        series: {
            type: 'sankey',
            layout: 'none',
            focusNodeAdjacency: 'allEdges',
            data: [{
                name: 'a'
            }, {
                name: 'b'
            }, {
                name: 'a1'
            }, {
                name: 'a2'
            }, {
                name: 'b1'
            }, {
                name: 'c'
            }],
            links: [{
                source: 'a',
                target: 'a1',
                value: 5
            }, {
                source: 'a',
                target: 'a2',
                value: 3
            }, {
                source: 'b',
                target: 'b1',
                value: 8
            }, {
                source: 'a',
                target: 'b1',
                value: 3
            }, {
                source: 'b1',
                target: 'a1',
                value: 1
            }, {
                source: 'b1',
                target: 'c',
                value: 2
            }]
        }
    };
    

    从代码可以看出,echars的桑基图主要有两个基本概念:

    • 节点 (nodes):表示所有有关系的节点
    • 连接 (links): 源节点至目标节点之间的关系,每个连接包括三个元素:
      • source: 源节点
      • target: 目标节点
      • value: 数据

    桑吉图的作用:

    可用于数据从一系列节点到另一系列节点流入流出的可视化。例如: 图书章节,资金流向,渠道分析,用户行为分析。

    开始实践

    需求场景

    做一个app用户行为分析,点击某个节点或支流流向,能后点亮整个链路。

    实践效果

    前端高手系列-echarts桑基图运用

    代码实现

    初步配置达到预览效果,可以将以下代码复制到echarts的编辑器中查看效果

    option = {
        series: {
            type: 'sankey',
            layout: 'none',
            focusNodeAdjacency: 'allEdges',
            data: [{
                name: '进入',
             
               
            }, {
                name: '首页'
                
            }, {
                name: '个人中心'
            }, {
                name: '购物车'
            },
             {
                name: '商品'
            },
              {
                name: '订单'
            }],
            links: [{
         
          source: '进入',
          target: '首页',
          value: 5,
        },
        {
          source: '进入',
          target: '个人中心',
      
          value: 3,
        },
        {
       
          source: '个人中心',
          target: '购物车',
          value: 8,
        },
        {
        
          source: '购物车',
          target: '商品',
          value: 8,
        },
        {
        
          source: '个人中心',
          target: '订单',
          value: 9,
        },]
        }
    };
    
    
    

    实现能点击某个节点或支流流向,能后点亮整个链路。

    myChart.showLoading()
    
    let option
    let links=[]
    $.get(ROOT_PATH + '/data/asset/data/energy.json', function (data) {
      myChart.hideLoading()
      let node = [
        {
          name: '进入',
        },
        {
          name: '首页',
        },
        {
          name: '个人中心',
        },
        {
          name: '购物车',
        },
        {
          name: '商品',
        },
        {
          name: '订单',
        },
      ]
      links = [
        {
         
          source: '进入',
          target: '首页',
          value: 5,
        },
        {
          source: '进入',
          target: '个人中心',
      
          value: 3,
        },
        {
       
          source: '个人中心',
          target: '购物车',
          value: 8,
        },
        {
        
          source: '购物车',
          target: '商品',
          value: 8,
        },
        {
        
          source: '个人中心',
          target: '订单',
          value: 9,
        },
      ]
      option = {
        title: {
          text: 'Sankey Diagram',
        },
        tooltip: {
          trigger: 'item',
          triggerOn: 'mousemove',
        },
        series: [
          {
            type: 'sankey',
            data: node,
            links: links,
            // focusNodeAdjacency: 'allEdges',
            itemStyle: {
              borderWidth: 1,
              borderColor: '#aaa',
            },
            lineStyle: {
              color: 'source',
              curveness: 0.5,
            },
          },
        ],
      }
      getLastLevelNodes()
      findFirstNode()
      myChart.setOption(option)
    })
    let currentItemObj
    let rootLinks = []
    let leftNodesArr = []
    let rightNodesArr = []
    let lastLevelNodesArr = []
    let headsArr = [];
    function findFirstNode(){
    	//当前source 不在其他target中
    	  	let headNodesArr = [];
    		  links.forEach((link,index,arr) => {
    			  if(arr.every((i)=>{
    				 return link.source !=i.target
    			  })){
    				 headNodesArr.push(link.source)
    				}	  
    				  
      })
    	headsArr = Array.from(new Set(headNodesArr))
    	console.log('headsArr',headsArr)
    }
    
    function isLastLevelNode(node) {
      let sourceArr = []
      let targetArr = []
      option.series[0].links.forEach((link) => {
        if (node.name === link.source) {
          sourceArr.push(link)
        } else if (node.name === link.target) {
          targetArr.push(link)
        }
      })
      return targetArr.length > 0 && sourceArr.length === 0
    }
    // 拿到所有末级节点数组
    function getLastLevelNodes() {
      lastLevelNodesArr = []
      option.series[0].data.forEach((node) => {
        if (isLastLevelNode(node)) {
          lastLevelNodesArr.push(node)
        }
      })
    }
    function findLeftLink(obj) {
      console.log('findLeftLink obj', obj)
      if (!Object.prototype.toString.call(obj) === '[object Object]') return
      leftNodesArr.push(obj)
    
      if(headsArr.includes(obj.source)){
              return ''
      }
      let nextObj = option.series[0].links.find((item) => item.target == obj.source)
      console.log('findLeftLink nextObj', nextObj)
    
      return nextObj && findLeftLink(nextObj)
    }
    
    function findRightLink(obj) {
    
      if (!obj) {
        return
      }
      rightNodesArr.push(obj)
      option.series[0].links
        .filter((item) => item.source == obj.target)
        .map((i) => findRightLink(i))
    }
    
    myChart.on('click', function (params) {
      console.log('params:', params)
      console.log('links:', option.series[0].links)
      option.series[0].links.forEach((item) => {
        if (item.hasOwnProperty('value')) {
          delete item.lineStyle
        }
      })
      let currentItem = params.data
      leftNodesArr = []
      rightNodesArr = []
      rootLinks = []
      if (!currentItem.hasOwnProperty('value')) {
        // 点击的节点
        console.log('currentItem:点击的节点', currentItem)
        currentItemObj = option.series[0].links.find(
          (o) => o.target == currentItem.name
        )
        if (currentItemObj) {
          findLeftLink(currentItemObj)
          // 如果不是是末级节点
          if (!lastLevelNodesArr.find((v) => v.name === currentItem.name)) {
            findRightLink(currentItemObj)
          }
        } else {
          // 如果是1级节点
        
          option.series[0].links.forEach((link) => {
            if (link.source == currentItem.name) {
              console.log('nn link:', link)
              findRightLink(link)
            }
          })
        }
        console.log('currentItem:点击的节点', currentItemObj)
      } else {
        // 点击的线
        console.log('currentItem: 点击的线', currentItem)
        currentItemObj = currentItem
        findLeftLink(currentItemObj)
        findRightLink(currentItemObj)
      }
    
      console.log('左边的节点leftNodesArr', leftNodesArr)
      console.log('右边的节点rightNodesArr', rightNodesArr)
    
      // let matchedNodes = Array.from(new Set(leftNodesArr.concat(rightNodesArr)))
      // console.log('matchedNodes', matchedNodes)
      if (!currentItem.hasOwnProperty('value')) {
          //第一个是不是根节点
        if (rightNodesArr.length > 1 && !headsArr.includes(rightNodesArr[1].source)) {
          
          rightNodesArr = rightNodesArr.slice(1)
        }
      }
      console.log('右边的节点rightNodesArr', rightNodesArr)
      option.series[0].links.forEach((item) => {
        rightNodesArr.forEach((v) => {
          if (item.target === v.target) {
            item.lineStyle = {
              color: 'red',
            }
          }
        })
      })
    
      myChart.setOption(option)
    })
    
    

    运用的知识点

    • 函数递归
    • 数组去重
    • echats操作

    起源地下载网 » 前端高手系列-echarts桑基图运用

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元