跳至內容

階層

在計算 階層配置 之前,您需要一個根節點。如果您的資料已經是階層格式,例如 JSON,您可以直接將其傳遞給 hierarchy;否則,您可以使用 stratify 將表格資料(例如逗號分隔值 (CSV))重新排列成階層。

hierarchy(data, children)

範例 · 原始碼 · 從指定的階層 data 建構一個根節點。指定的 data 必須是一個表示根節點的物件。例如

js
const data = {
  name: "Eve",
  children: [
    {name: "Cain"},
    {name: "Seth", children: [{name: "Enos"}, {name: "Noam"}]},
    {name: "Abel"},
    {name: "Awan", children: [{name: "Enoch"}]},
    {name: "Azura"}
  ]
};

建構階層

js
const root = d3.hierarchy(data);

指定的 children 存取器函式會針對每個資料呼叫,從根 data 開始,並且必須傳回一個表示子項目的資料可迭代物件(如果有的話)。如果未指定子項目存取器,它會預設為

js
function children(d) {
  return d.children;
}

如果 data 是 Map,它會隱式轉換為項目 [undefined, data],而子項目存取器則預設為

js
function children(d) {
  return Array.isArray(d) ? d[1] : null;
}

這允許您將 grouprollup 的結果傳遞給 hierarchy。

傳回的根節點和每個後代具有下列屬性

  • node.data - 傳遞給 hierarchy 的關聯資料
  • node.depth - 根節點為零,每個後代世代增加一
  • node.height - 距離任何後代葉節點最遠的距離,或葉節點為零
  • node.parent - 父節點,或根節點為 null
  • node.children - 子節點陣列,如果有,或葉節點為未定義
  • node.value - 節點及其 後代 的可選總和值

此方法也可用于測試節點是否為 instanceof d3.hierarchy 以及擴充節點原型。

node.ancestors()

來源 · 傳回祖先節點陣列,從此節點開始,然後是每個父節點直到根節點。

node.descendants()

來源 · 傳回後代節點陣列,從此節點開始,然後是每個子節點,依循拓撲順序。

node.leaves()

來源 · 傳回葉節點陣列,依循遍歷順序。葉節點 是沒有子節點的節點。

node.find(filter)

來源 · 傳回從此 node 開始的層級中第一個節點,指定 filter 會傳回真值。如果找不到此類節點,則傳回未定義。

node.path(target)

來源 · 傳回從此 node 到指定 target 節點的層級中路徑最短。路徑從此 node 開始,上升到此 nodetarget 節點的最近共同祖先,然後下降到 target 節點。這對於 階層式邊緣綑綁 很實用。

來源 · 傳回此 node 和其後代的連結陣列,其中每個 連結 都是定義來源和目標屬性的物件。每個連結的來源是父節點,目標是子節點。

node.sum(value)

範例 · 來源 · 評估此 node後序遍歷 中每個後代的指定 value 函數,並傳回此 node。每個節點的 node.value 屬性設定為指定函數傳回的數值加上所有子節點的組合值。函數傳入節點的資料,且必須傳回非負數。value 存取器會評估 node 和每個後代,包含內部節點;如果您只想讓葉節點有內部值,則傳回任何有子節點的節點為零。 例如,作為 node.count 的替代方法

js
root.sum((d) => d.value ? 1 : 0);

您必須在呼叫需要 node.value 的階層配置之前呼叫 node.sum 或 node.count,例如 樹狀圖。例如

js
// Construct the treemap layout.
const treemap = d3.treemap();
treemap.size([width, height]);
treemap.padding(2);

// Sum and sort the data.
root.sum((d) => d.value);
root.sort((a, b) => b.height - a.height || b.value - a.value);

// Compute the treemap layout.
treemap(root);

// Retrieve all descendant nodes.
const nodes = root.descendants();

由於 API 支援 方法串接,您也可以說

js
d3.treemap()
    .size([width, height])
    .padding(2)
  (root
      .sum((d) => d.value)
      .sort((a, b) => b.height - a.height || b.value - a.value))
  .descendants()

這個範例假設節點資料有一個值欄位。

node.count()

範例 · 原始碼 · 計算此 node 下的葉子數量,並將其指定給 node.value,對 node 的每個後代也做同樣的事。如果此 node 是葉子,其計數為一。傳回此 node。另請參閱 node.sum

node.sort(compare)

範例 · 原始碼 · 對此 node 的子節點(如有)以及此 node 的每個後代的子節點,使用指定的 compare 函式,以 前序遍歷 進行排序,並傳回此 node

指定的函式會傳入兩個節點 ab 以進行比較。如果 a 應該在 b 之前,函式必須傳回小於零的值;如果 b 應該在 a 之前,函式必須傳回大於零的值;否則,ab 的相對順序未指定。請參閱 array.sort 以取得更多資訊。

node.sum 不同,compare 函式傳入的是兩個 節點,而不是兩個節點的資料。例如,如果資料有一個值屬性,這會根據節點及其所有後代的遞減總計值對節點進行排序,這建議用於 圓形包裝

js
root
    .sum((d) => d.value)
    .sort((a, b) => b.value - a.value);

類似地,要根據遞減高度(與任何後代葉子的最遠距離)然後根據遞減值對節點進行排序,建議用於 樹狀圖冰柱圖

js
root
    .sum((d) => d.value)
    .sort((a, b) => b.height - a.height || b.value - a.value);

要根據遞減高度然後根據遞增 ID 對節點進行排序,建議用於 樹狀圖

js
root
    .sum((d) => d.value)
    .sort((a, b) => b.height - a.height || d3.ascending(a.id, b.id));

如果您希望新的排序順序影響佈局,則必須在呼叫階層式佈局之前呼叫 node.sort;請參閱 node.sum 以取得範例。

node[Symbol.iterator]()

來源 · 傳回一個在廣度優先順序中迭代 node 的後代的迭代器。例如

js
for (const descendant of node) {
  console.log(descendant);
}

node.each(function, that)

範例 · 來源 · 為 node廣度優先順序 中的每個後代呼叫指定的 function,因此只有在較小深度的所有節點和相同深度中的所有前置節點都已拜訪過後,才會拜訪給定的 node。指定的函數會傳遞目前的 descendant、以 0 為基礎的遍歷 index 和此 node。如果指定了 that,則它是 callback 的 this context。

node.eachAfter(function, that)

範例 · 來源 · 為 node後序遍歷 中的每個後代呼叫指定的 function,因此只有在所有後代都已拜訪過後,才會拜訪給定的 node。指定的函數會傳遞目前的 descendant、以 0 為基礎的遍歷 index 和此 node。如果指定了 that,則它是 callback 的 this context。

node.eachBefore(function, that)

範例 · 來源 · 為 node前序遍歷 中的每個後代呼叫指定的 function,因此只有在所有祖先都已拜訪過後,才會拜訪給定的 node。指定的函數會傳遞目前的 descendant、以 0 為基礎的遍歷 index 和此 node。如果指定了 that,則它是 callback 的 this context。

node.copy()

來源 · 傳回從此 node 開始的子樹的深度拷貝。(不過,傳回的深度拷貝共用相同的資料。)傳回的節點是新樹的根;傳回節點的父節點永遠為 null,而其深度永遠為零。