AntvG6-graph圖譜工具

紫槐發表於2024-03-26

1 快速上手

1.1 在專案中使用 npm 包引入

Step 1: 使用命令列在專案目錄下執行以下命令

npm install --save @antv/g6

Step 2: 在需要用的 G6 的 JS 檔案中匯入

import G6 from '@antv/g6';

1.2 在 HTML 中使用 CDN 引入

<script src="https://gw.alipayobjects.com/os/antv/pkg/_antv.g6-{$version}/build/g6.js"></script>

注意

  • {$version} 中填寫版本號,例如 3.2.0
  • 最新版為 3.2.0,可以在 npm 檢視最新版本;
  • 詳情參考 Github 分支:https://github.com/antvis/g6/tree/master

2 快速試用

建立一個 G6 的關係圖僅需要下面幾個步驟:

  • 建立關係圖的 HTML 容器;
  • 資料準備;
  • 建立關係圖;
  • 配置資料來源,渲染。

Step 1: 建立容器

<div id="mountNode"></div>

Step 2: 資料準備

引入 G6 的資料來源為 JSON 格式的物件。該物件中需要有節點(nodes)和邊(edges)欄位,分別用陣列表示:

const data = {
  // 點集
  nodes: [
    {
      id: 'node1', // String,該節點存在則必須,節點的唯一標識
      x: 100, // Number,可選,節點位置的 x 值
      y: 200, // Number,可選,節點位置的 y 值
    },
    {
      id: 'node2', // String,該節點存在則必須,節點的唯一標識
      x: 300, // Number,可選,節點位置的 x 值
      y: 200, // Number,可選,節點位置的 y 值
    },
  ],
  // 邊集
  edges: [
    {
      source: 'node1', // String,必須,起始點 id
      target: 'node2', // String,必須,目標點 id
    },
  ],
};

注意

  • nodes 陣列中包含節點物件,唯一的 id 是每個節點物件中必要的屬性,xy 用於定位;
  • edges 陣列中包含邊物件,source 和 target 是每條邊的必要屬性,分別代表了該邊的起始點 id 與 目標點 id
  • 點和邊的其他屬性參見連結:圖元素配置文件

Step 3: 建立關係圖

建立關係圖(例項化)時,至少需要為圖設定容器、寬和高。

const graph = new G6.Graph({
  container: 'mountNode', // String | HTMLElement,必須,在 Step 1 中建立的容器 id 或容器本身
  width: 800, // Number,必須,圖的寬度
  height: 500, // Number,必須,圖的高度
});

Step 4: 配置資料來源,渲染

建立關係圖(例項化)時,至少需要為圖設定容器、寬和高。

graph.data(data); // 讀取 Step 2 中的資料來源到圖上
graph.render(); // 渲染圖

最終的結果

efa007de18a21082cdb17820d9fd7d2d.jpeg

3 配置

3.1 元素及其配置

圖的元素特指圖上的節點Node和邊Edge,不論是節點還是邊,它們的屬性分為兩種:

  • 樣式屬性 style:對應 Canvas 中的各種樣式,在元素狀態State 發生變化時,可以被改變;
  • 其他屬性:例如圖形( shape)、id(id )一類在元素狀態State發生變化時不能被改變的屬性。
    例如,G6 設定 hover 或 click 節點,造成節點狀態的改變,只能自動改變節點的樣式屬性(如 fillstroke其他屬性(如 shape 等)不能被改變。如果需要改變其他屬性,要透過 graph.updateItem 手動配置。樣式屬性是一個名為 style 的物件, style 欄位與其他屬性並行。

以節點元素為例,其屬性的資料結構如下:

{
  id: 'node0',          // 元素的 id
  shape: 'circle',      // 元素的圖形
  size: 40,             // 元素的大小
  label: 'node0'        // 標籤文字
  labelCfg: {           // 標籤配置屬性
    positions: 'center',// 標籤的屬性,標籤在元素中的位置
    style: {            // 包裹標籤樣式屬性的欄位 style 與標籤其他屬性在資料結構上並行
      fontSize: 12      // 標籤的樣式屬性,文字字型大小
    }
  }
  // ...,                  // 其他屬性
  style: {              // 包裹樣式屬性的欄位 style 與其他屬性在資料結構上並行
    fill: '#000',       // 樣式屬性,元素的填充色
    stroke: '#888',     // 樣式屬性,元素的描邊色
    // ...                 // 其他樣式屬性
  }
}

邊元素的屬性資料結構與節點元素相似,只是其他屬性中多了 source 和 target 欄位,代表起始和終止節點的 id

全域性配置

適用場景:所有節點統一的屬性配置,所有邊統一的屬性配置。使用方式:使用圖的兩個配置項:

defaultNode:節點在預設狀態下的樣式屬性(style)和其他屬性;
defaultEdge:邊在預設狀態下的樣式屬性(style)和其他屬性。

defaultNode: {
    size: 30, // 節點大小
    // ...                 // 節點的其他配置
    // 節點樣式配置
    style: {
      fill: 'steelblue', // 節點填充色
      stroke: '#666', // 節點描邊色
      lineWidth: 1, // 節點描邊粗細
    },
    // 節點上的標籤文字配置
    labelCfg: {
      // 節點上的標籤文字樣式配置
      style: {
        fill: '#fff', // 節點標籤文字顏色
      },
    },
  },
  // 邊在預設狀態下的樣式配置(style)和其他配置
  defaultEdge: {
    // ...                 // 邊的其他配置
    // 邊樣式配置
    style: {
      opacity: 0.6, // 邊透明度
      stroke: 'grey', // 邊描邊顏色
    },
    // 邊上的標籤文字配置
    labelCfg: {
      autoRotate: true, // 邊上的標籤文字根據邊的方向旋轉
    },
  },

3.2 使用圖佈局 Layout

當資料中沒有節點位置資訊,或者資料中的位置資訊不滿足需求時,需要藉助一些佈局演算法對圖進行佈局。G6 提供了 7 種一般圖的佈局和 4 種樹圖的佈局:

一般圖:

  • Random Layout:隨機佈局;
  • Force Layout:經典力導向佈局:
  • Circular Layout:環形佈局;
  • Radial Layout:輻射狀佈局;
  • MDS Layout:高維資料降維演算法佈局;
  • Fruchterman Layout:Fruchterman 佈局,一種力導佈局;
  • Dagre Layout:層次佈局。

樹圖佈局:

  • Dendrogram Layout:樹狀佈局(葉子節點佈局對齊到同一層);
  • CompactBox Layout:緊湊樹佈局;
  • Mindmap Layout:腦圖佈局;
  • Intended Layout:縮排佈局。
const graph = new G6.Graph({
  ...                      // 其他配置項
  layout: {                // Object,可選,佈局的方法及其配置項,預設為 random 佈局。
    type: 'force',         // 指定為力導向佈局
    preventOverlap: true,  // 防止節點重疊
    // nodeSize: 30,       // 節點大小,用於演算法中防止節點重疊時的碰撞檢測。由於已經在上一節的元素配置中
    linkDistance: 100,     // 指定邊距離為100設定了每個節點的 size 屬性,則不需要在此設定 nodeSize。
    center: [500, 300]
  }
});

更多屬性(https://g6.antv.vision/zh/docs/api/graphLayout/guide)

3.3 圖的互動 Behavior

G6 中的互動行為。G6 內建了一系列互動行為,使用者可以直接使用。簡單地理解,就是可以一鍵開啟這些互動行為:

  • drag-canvas:拖拽畫布;
  • zoom-canvas:縮放畫布。

更多詳見:互動行為 Behavior

const graph = new G6.Graph({
  // ...                                          // 其他配置項
  modes: {
    default: ['drag-canvas', 'zoom-canvas', 'drag-node'], // 允許拖拽畫布、放縮畫布、拖拽節點
  },
});
  • activate-relations
    含義:當滑鼠移到某節點時,突出顯示該節點以及與其直接關聯的節點和連線;

引數:

  • trigger: 'mouseenter'。可以是 mousenter,表示滑鼠移入時觸發;也可以是 click,滑鼠點選時觸發;
  • activeState: 'active'。活躍節點狀態。當行為被觸發,需要被突出顯示的節點和邊都會附帶此狀態,預設值為 active;可以與 graph 例項的 nodeStyle 和 edgeStyle 結合實現豐富的視覺效果。
  • inactiveState: 'inactive'。非活躍節點狀態。不需要被突出顯示的節點和邊都會附帶此狀態。預設值為 * * * inactive。可以與 graph 例項的 nodeStyle 和 edgeStyle 結合實現豐富的視覺效果;
  • resetSelected:高亮相連節點時是否重置已經選中的節點,預設為 false,即選中的節點狀態不會被 activate-relations 覆蓋;
{
  type: 'activate-relations',
  activeState: 'actives',
  inactiveState: 'inactives',
  resetSelected: false
},
// 當前節點的多狀態樣式
nodeStateStyles: {
  actives: {
    opacity: 1,
    lineWidth: 0
  },
  inactives: {
    opacity: 0.2,
    lineWidth: 0
  }
},
edgeStateStyles: {
  actives: {
    opacity: 1
  },
  inactives: {
    opacity: 0.2
  }
}

https://g6.antv.vision/zh/docs/manual/middle/states/defaultBehavior)

3.4 監聽和繫結事件

  • 全域性事件
    只要在畫布上範圍內發生均會被觸發,如 mousedown,mouseup,click,mouseenter,mouseleave 等。
graph.on('click', (ev) => {
  const shape = ev.target;
  const item = ev.item;
  if (item) {
    const type = item.getType();
  }
});
  • canvas 事件
    只在 canvas 空白處被觸發,如 canvas:mousedown,canvas:click 等,以canvas:eventName 為事件名稱。
graph.on('canvas:click', (ev) => {
  const shape = ev.target;
  const item = ev.item;
  if (item) {
    const type = item.getType();
  }
});
  • 節點/邊/combo 上的事件
    例如 node:mousedown,edge:click, combo:click 等,以 type:eventName 為事件名稱。
graph.on('node:click', (ev) => {
  const node = ev.item; // 被點選的節點元素
  const shape = ev.target; // 被點選的圖形,可根據該資訊作出不同響應,以達到區域性響應效果
  // ... do sth
});

graph.on('edge:click', (ev) => {
  const edge = ev.item; // 被點選的邊元素
  const shape = ev.target; // 被點選的圖形,可根據該資訊作出不同響應,以達到區域性響應效果
  // ... do sth
});

graph.on('combo:click', (ev) => {
  const combo = ev.item; // 被點選 combo 元素
  const shape = ev.target; // 被點選的圖形,可根據該資訊作出不同響應,以達到區域性響應效果
  // ... do sth
});
  • 圖形上的事件
    指定圖形上的事件,如 circle-shape:mousedown,circle-shape:click 等,以 shapeName:eventName 為事件名稱。可用於繫結節點/邊/combo 中對區域性圖形做出響應的場景。效果類似上文 graph.on('node:click', fn) 中透過 target 資訊作出不同響應。

關於圖形的 name:

內建節點/邊/combo 上每個圖形的名稱在開發過程中可以透過 graph.on('node:click', (ev) => console.log(ev.target.get('name'))) 得知;

自定義節點/邊/combo 中透過 addShape 增加的圖形,可新增與 attrs 平級的 name 欄位指定任意(同元素中唯一)字串作為 name。請注意同個元素(節點/邊/combo)中不同圖形儘量給予不同的 name 值。

下面例子為圖中所有 name 為 circle-shape 的圖形繫結了 click 事件監聽:

graph.on('circle-shape:click', (ev) => {
  const shape = ev.target; // 被點選的圖形
  // ... do sth
});
  • 時機事件

時機事件指渲染、視口變換、元素增刪改、資料變換等時機。所有時機事件詳見 G6 的時機事件列表。如:beforeadditemafteradditem 等:

  • 節點/邊/Combo 狀態改變時的事件:beforerefreshitemafterrefreshitem
  • 佈局時機:beforelayoutafterlayout

下面例子為 graph 繫結了渲染完成時機的監聽。時機事件中,afterrender、afterlayout 一類事件必須在 graph.render()graph.read() 之前繫結,方可監聽到首次渲染、佈局完成後的相關事件。

graph.on('afterrender', (ev) => {
  // ... do sth
});
  • 自定義事件

G6 允許使用者自定義任意事件,可在任意位置透過 graph.emit(customEventName: string, event: IG6GraphEvent) 觸發一個事件,第一個引數為自定義事件名稱。在觸發前,透過 graph.on(customEventName: string, callback: Function) 進行監聽。例如:

graph.on('some-custom-event-name', (ev) => {
  // ... do sth
});
graph.emit('some-custom-event-name', {
  // some params
})

ps:當資料多樣化的時候,可以對不同的資料設定不同的節點或者邊的樣式

data.nodes.forEach((node) => {
  node.style = {
    fill: node.type === 'company'
      ? '#EE5555'
      : node.type === 'director'
        ? '#0F8CFF'
        : '#FFC510',
    stroke: node.type === 'company'
      ? '#EE5555'
      : node.type === 'director'
        ? '#0F8CFF'
        : '#FFC510'
  }
})
data.edges.forEach((edge) => {
  edge.style = {
    stroke: edge.typest === 0
      ? '#EE5555'
      : edge.typest === 1
        ? '#0F8CFF'
        : '#FFC510'
  }
  edge.label = edge.typest === 0
    ? '董事'
    : edge.typest === 1
      ? '經理'
      : edge.typest === 2
        ? '職員'
        : null
  edge.labelCfg = {
    style: {
      fill: edge.typest === 0
        ? '#EE5555'
        : edge.typest === 1
          ? '#0F8CFF'
          : '#FFC510'
    }
  }
})

相關文章