<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ECharts 热图实现</title>
    <!-- 引入ECharts -->
    <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
    <style>
      #chartContainer {
        width: 800px;
        height: 600px;
        margin: 0 auto;
      }
    </style>
  </head>
  <body>
    <div id="chartContainer"></div>

    <script>
      // 初始化图表
      const myChart = echarts.init(document.getElementById('chartContainer'))

     


     

      // 响应窗口大小变化
      window.addEventListener('resize', function () {
        myChart.resize()
      })

      var graph = {
        nodes: [
          {
            name: 'A',
            value: ['教授', '在职', '党委办公室、校长办公室'],
            category: '中心教师',
            symbolSize: 50,
            tooltip: {
              formatter: '{b0}:{c0}',
            },
          },
          {
            name: 'B',
            category: '论文',
            value: ['期刊论文', '2005'],
            symbolSize: 20,
            tooltip: {
              formatter: '{b0}:{c0}',
            },
          },
          {
            name: 'C',
            category: '论文合作教师',
            symbolSize: 50,
          },

          {
            name: 'D',
            category: '项目',
            value: ['信息与通信工程学院', '立项日期：20131101'],
            symbolSize: 20,
            tooltip: {
              formatter: '{b0}:{c0}',
            },
          },
          {
            name: 'N',
            category: '项目合作教师',
            symbolSize: 50,
          },
          {
            name: 'Q',
            category: '项目',
            symbolSize: 20,
          },

          {
            name: 'S',
            category: '项目',
            symbolSize: 20,
          },
          {
            name: 'E',
            category: '专著专利',
            symbolSize: 20,
            value: ['专利文献', '2009-07-21'],
            tooltip: {
              formatter: '{b0}:{c0}',
            },
          },
          {
            name: 'W',
            category: '专著专利',
            symbolSize: 20,
          },
          {
            name: 'Y',
            category: '专著专利',
            symbolSize: 20,
          },
          {
            name: 'Z',
            category: '专著专利',
            symbolSize: 20,
          },
          {
            name: 'F',
            category: '专著专利合作教师',
            symbolSize: 50,
          },
          {
            name: 'O',
            category: '专著专利合作教师',
            symbolSize: 50,
          },
          {
            name: 'P',
            category: '专著专利合作教师',
            symbolSize: 50,
          },
          {
            value: ['信息与通信工程学院', '信息工程 '],
            name: 'G',
            category: '课程',
            symbolSize: 20,
            tooltip: {
              formatter: '{b0}:{c0}',
            },
          },
          {
            name: 'I',
            category: '课程',
            symbolSize: 20,
          },
          {
            name: 'L',
            category: '课程',
            symbolSize: 20,
          },
          {
            name: 'H',
            category: '课程合作教师',
            symbolSize: 50,
          },
          {
            name: 'M',
            category: '课程合作教师',
            symbolSize: 50,
          },
        ],
        links: [
          {
            source: 'A',
            target: 'B',
          },
          {
            source: 'B',
            target: 'C',
          },
          {
            source: 'A',
            target: 'D',
          },
          {
            source: 'D',
            target: 'N',
          },
          {
            source: 'N',
            target: 'Q',
          },
          {
            source: 'N',
            target: 'R',
          },
          {
            source: 'A',
            target: 'E',
          },
          {
            source: 'E',
            target: 'F',
          },
          {
            source: 'F',
            target: 'W',
          },
          {
            source: 'F',
            target: 'Y',
          },
          {
            source: 'P',
            target: 'Z',
          },
          {
            source: 'E',
            target: 'O',
          },
          {
            source: 'E',
            target: 'P',
          },
          {
            source: 'A',
            target: 'G',
          },
          {
            source: 'G',
            target: 'H',
          },
          {
            source: 'G',
            target: 'M',
          },
          {
            source: 'M',
            target: 'I',
          },
          {
            source: 'M',
            target: 'L',
          },
        ],
      }
      const defaultCategory = '中心教师'
      const graphTitle = '力导向关系图--实现点击节点展开折叠'
      const currentGraph = {
        nodes: {},
        links: {},
      }
      const nodeMap = {}
      // 页面加载时，第一次初始化图
      function init() {
        // 根据定义的常量，产生currentGraph的默认数据
        // 遍历全部nodes和links，产生node映射map
        for (let i = 0; i < graph.nodes.length; i++) {
          if (graph.nodes[i].category === defaultCategory) {
            currentGraph.nodes[graph.nodes[i].name] = graph.nodes[i]
          }
          nodeMap[graph.nodes[i].name] = graph.nodes[i]
          nodeMap[graph.nodes[i].name]['links'] = {}
          nodeMap[graph.nodes[i].name]['nodes'] = {}
          nodeMap[graph.nodes[i].name]['hasAppend'] = false
        }
        for (let i = 0; i < graph.links.length; i++) {
          let link = graph.links[i]
          if (
            nodeMap[link.source] !== undefined &&
            nodeMap[link.target] !== undefined
          ) {
            nodeMap[link.source].links[link.target] = link
            nodeMap[link.source].nodes[nodeMap[link.target].name] =
              nodeMap[link.target]
          }
        }

        for (let i = 0; i < graph.nodes.length; i++) {
          graph.nodes[i].itemStyle = null
          graph.nodes[i].label = {
            normal: {
              show: graph.nodes[i].symbolSize > 15,
            },
          }
        }
        redrawGraph()
      }
      // 处理点击节点展开
      function append(nodeName) {
        // 根据nodeName从nodeMap里拿出对应的nodes和links，并append到currentGraph.nodes currentGraph.links
        let node = nodeMap[nodeName]
        if (
          node.hasAppend === true ||
          Object.keys(node.nodes).length === 0 ||
          Object.keys(node.links).length === 0
        ) {
          alert('无法继续展开')
          return
        }
        Object.values(node.nodes).forEach((n) => {
          currentGraph.nodes[n.name] = n
        })
        Object.values(node.links).forEach((l) => {
          currentGraph.links[l.source + '_' + l.target] = l
        })
        node.hasAppend = true
        redrawGraph()
      }
      // 处理点击节点收缩
      function remove(nodeName) {
        //根据nodeName从nodeMap里拿出对应的nodes和links，从currentGraph.nodes currentGraph.links删除当前节点的nodes和links并且递归
        let node = nodeMap[nodeName]
        Object.values(node.nodes).forEach((n) => {
          delete currentGraph.nodes[n.name]
          if (n.hasAppend === true && Object.keys(n.nodes).length > 0) {
            remove(n.name)
          }
        })
        Object.values(node.links).forEach((l) => {
          delete currentGraph.links[l.source + '_' + l.target]
        })
        // 设置flag 等于false
        node.hasAppend = false

        redrawGraph()
      }
      // 根据更新后的option重新画图
      function redrawGraph() {
        option.series[0].data = Object.values(currentGraph.nodes)
        option.series[0].links = Object.values(currentGraph.links)
        console.log(option)
        myChart.setOption(option)
      }
      const option = {
        title: {
          text: graphTitle,
          top: 'top',
          left: 'center',
        },
        tooltip: {},
        legend: [],
        animation: false,
        series: [
          {
            type: 'graph',
            layout: 'force',
            data: Object.values(currentGraph.nodes),
            links: Object.values(currentGraph.links),
            categories: [
              {
                name: '中心教师',
                itemStyle: {
                  color: '#c23531',
                },
              },
              {
                name: '专著专利合作教师',
                itemStyle: {
                  color: '#749f83',
                },
              },
              {
                name: '课程合作教师',
                itemStyle: {
                  color: '#6e7074',
                },
              },
              {
                name: '论文合作教师',
                itemStyle: {
                  color: '#2f4554',
                },
              },
              {
                name: '论文',
                itemStyle: {
                  color: '#61a0a8',
                },
              },
              {
                name: '专著专利',
                itemStyle: {
                  color: '#91c7ae',
                },
              },
              {
                name: '课程',
                itemStyle: {
                  color: '#999ea4',
                },
              },
              {
                name: '项目合作教师',
                itemStyle: {
                  color: '#DEB887',
                },
              },
              {
                name: '项目',
                itemStyle: {
                  color: '#bda29a',
                },
              },
            ],
            roam: true,
            focusNodeAdjacency: false,
            itemStyle: {
              normal: {
                borderColor: '#fff',
                borderWidth: 1,
                shadowBlur: 10,
                shadowColor: 'rgba(0, 0, 0, 0.3)',
              },
            },
            label: {
              position: 'right',
              formatter: '{b}',
            },
            lineStyle: {
              color: 'target',
              opacity: 0.6,
              curveness: 0.3,
            },
            emphasis: {
              lineStyle: {
                width: 10,
              },
            },
            force: {
              layoutAnimation: false,
              repulsion: 500,
            },
          },
        ],
      }
      init()


      // 设置配置项
      myChart.setOption(option)
      myChart.on('click', function (params) {
        if (params.dataType === 'node') {
          const node = nodeMap[params.data.name]
          if (node.hasAppend === true) {
            remove(node.name)
          } else {
            append(node.name)
          }
        }
      })
    </script>
  </body>
</html>
