Echarts+Vue 實現知識圖譜


需求描述

把一類錯綜復雜的知識點按照相關性規則連線,客觀匯總展現出來,切換類型可動態刷新圖譜,圖譜節點能點擊交互。

實現效果

image.png

實現思路

先格式化處理后台拿到的數據,再利用Echarts 的 graph 類型圖庫進行配置繪制。

代碼實現

先用mock造個數據實現接口,其中圖譜數據中的 name就是節點展示的內容,category 可以作為過濾條件給節點設置不同的顏色,若要設置特殊大小可以symbolSize設值, id是用來前后連線的標識。

/**
 * 圖譜數據源源
 */
export const data = [
    {
        id:1,
        name:'測試節點',
        categary:'1',
        symbolSize: 60
    },
    {
        id:2,
        name:'測試節點',
        categary:'1',
        symbolSize: 40
    },
    {
        id:3,
        name:'測試節點',
        categary:'2',
    },
    {
        id:4,
        name:'測試節點',
        categary:'',
    },
    {
        id:5,
        name:'測試節點測試節點',
        categary:'',
    },
    {
        id:6,
        name:'測試節點',
        categary:'2',
    },
    {
        id:7,
        name:'測試節點',
        categary:'',
    },
    {
        id:8,
        name:'測試節點',
        categary:'',
    },
    {
        id:9,
        name:'測試節點',
        categary:'',
    },
    {
        id:10,
        name:'測試節點',
        categary:'',測試節點
    }
];
//節點連線
let linkData = [
    {source: '2', target: '3', name: ''},
    {source: '3', target: '4', name: ''},
    {source: '3', target: '5', name: ''},
    {source: '5', target: '6', name: ''},
    {source: '5', target: '7', name: ''},
    {source: '5', target: '8', name: ''},
    {source: '9', target: '10', name: ''},
    {source: '10', target: '9', name: ''},
    {source: '1', target: '2' , name: ''},
    {source: '1', target: '10', name: ''}
    
]

/**
 * 模糊查詢大類
 * @param {*} name 
 */
export const search = (name)=>{
    return new Promise((resolve,reject)=>{
        let result = {
            seriesData: [],
            linksData: []
        }
        let list = data.filter(item=>item.name.indexOf(name)>=0)
        if(list&&list.length>0){
            result.seriesData = list ||[];
        }else{
            result.seriesData = data ||[];
        }
        result.linksData = linkData ||[];
        if(list.length>0){
            resolve(result)
        }else{
            reject()
        }
    })
}


export const getAllData = ()=>{
    return new Promise((resolve,reject)=>{
        let result = {
            seriesData: [],
            linksData: []
        }
        result.seriesData = data||[];
        result.linksData = linkData ||[];
        if(data.length>0){
            resolve(result)
        }else{
            reject()
        }
    })
}

/**
 * 分類2
 */
export const categarys =  ["建設用地"]

封裝一個chart組件,實現圖譜展示

<template>
  <div id="chart" class="chart"></div>
</template>
<script>
import { expendNodes } from "./mock";
var echarts = require("echarts/lib/echarts");
require("echarts/lib/chart/graph");
require("echarts/lib/component/tooltip");
require("echarts/lib/component/title");
export default {
  name: "Charts",
  props: {
    chartList: {
      type: Object,
      required: true,
    },
  },
  watch: {
    chartList: {
      handler(val) {
        this.formatData(val || [], true);
      },
    },
  },
  data() {
    return {
      myChart: "",
      seriesData: [],
      seriesLinks: [],
      categories:[],
      lastClickId: "",
      colors: ["#a3d2ca","#056676","#ea2c62","#16a596","#03c4a1","#f5a25d",
      "#8CD282","#32e0c4","#00FAE1","#f05454"], 
    };
  },
  methods: {
    /**
     * 節點點擊事件
     */
    async nodeClick(params) {
      const index = this.seriesData.findIndex(
        (item) => item.id === params.data.id
      );
       console.log('點了節點:'+index+1,"clicked");
    },
    /**
     * 設置echarts配置項,重繪畫布
     */
    initCharts() {
        const that = this;
      if (!this.myChart) {
        this.myChart = echarts.init(document.getElementById("chart"));
        this.myChart.on("click", (params) => {
          if (params.dataType === "node") {
            //判斷點擊的是圖表的節點部分
            this.nodeClick(params);
          }
        });
      }
      // 指定圖表的配置項和數據
      let option = {
        // 動畫更新變化時間
        animationDurationUpdate: 500,
        animationEasingUpdate: "quinticInOut",
        tooltip: {
          show: false,
        },
        series: [
          {
            type: "graph",
            layout: "force",
            legendHoverLink: true, //是否啟用圖例 hover(懸停) 時的聯動高亮。
            hoverAnimation: true, //是否開啟鼠標懸停節點的顯示動畫
            focusNodeAdjacency: true,
            edgeLabel: {
              position: "middle", //邊上的文字樣式
              normal: {
                show: true,
                textStyle: {
                  fontSize: 12,
                },
                position: "middle",
                formatter: function (x) {
                  return x.data.name;
                },
              },
            },
            edgeSymbol: ["", "arrow"],
            force: {
                edgeLength: 15,
                repulsion: 200,
            },
            roam: true,
            draggable: true, //每個節點的拖拉
            itemStyle: {
              normal: {
                color: "#00FAE1",
                cursor: "pointer",
                //color:Math.floor(Math.random()*16777215).toString(16),
                 //color: ['#fc853e','#28cad8','#9564bf','#bd407e','#28cad8','#fc853e','#e5a214'],
                label: {
                 show: true,
                  position: [-10, -15],
                  textStyle: {
                    //標簽的字體樣式
                    color: "#fff", //字體顏色
                    fontStyle: "normal", //文字字體的風格 'normal'標准 'italic'斜體 'oblique' 傾斜
                    fontWeight: "bold", //'normal'標准'bold'粗的'bolder'更粗的'lighter'更細的或100 | 200 | 300 | 400...
                    fontFamily: "sans-serif", //文字的字體系列
                    fontSize: 12, //字體大小
                  },
                  
                },
                nodeStyle: {
                  brushType: "both",
                  borderColor: "rgba(255,215,0,0.4)",
                  borderWidth: 1,
                },
              },
              //鼠標放上去有陰影效果
              emphasis: {
                shadowColor: "#00FAE1",
                shadowOffsetX: 0,
                shadowOffsetY: 0,
                shadowBlur: 40,
                
              },
            },
            lineStyle: {
              width: 2,
            
            },
            label: {
               fontSize: 18,
            },
            symbolSize: 24, //節點大小
            links: this.seriesLinks,
            data: this.seriesData,
            categories:this.categories,
            cursor: "pointer",
          },
        ],
      };
      // 使用剛指定的配置項和數據顯示圖表。
      this.myChart.setOption(option);
    },
    /**
     * 格式化數據到表格需要的數據
     */
    formatData(list, reset = false) {
     const that =this;
      let nodes = list.seriesData;
      this.seriesData = [];
      this.seriesLinks = [];
      let colorIndex = 0;
      let data =[];
      let loadedCat=[];
      nodes.forEach((item,index)=>{
          if(item.categary && loadedCat.indexOf(item.categary) === -1){
              colorIndex = Math.floor((Math.random()*that.colors.length));
              loadedCat.push(item.categary);
              this.categories.push({name:item.categary});
          }
           item.itemStyle = {
              color: that.colors[colorIndex],
              borderColor: '#ffffff'
            }
        data.push(item);
      })
      this.seriesData.push(...data);
      this.seriesLinks.push(...list.linksData);
      this.initCharts();
    },
    
  },
  beforeDestroy() {},
};
</script>
<style scoped>
.chart {
  height: 100%;
}
</style>

在其他組件中調用chart組件,並傳入展示的數據內容

 <Charts ref="charts" v-show="type === 2" :chartList="searchList" />

完畢!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM