Skip to content

Sankey

Dòng chảy

"Tất cả rồi sẽ đi đâu?" Một biểu đồ Sankey theo dõi dòng chảy qua một hệ thống: các nút được bố trí theo cột, và độ dày của mỗi dải chính là giá trị dòng chảy. Đây là hình ảnh phù hợp cho thương mại giữa các nhà xuất khẩu và thị trường, ngân sách từ nguồn đến nơi sử dụng, lưu lượng truy cập từ nguồn giới thiệu đến các trang - bất cứ nơi nào một đại lượng tách ra rồi hợp lại trên đường đi của nó.

Example
canvas · responsive
Tìm hiểu thêm: Hướng dẫn Insights·Hướng dẫn DevTools

Bố cục được tính toán bằng d3-sankey: các nút được gán vào các cột từ cấu trúc topology của đồ thị, sắp xếp theo chiều dọc, và các liên kết được vẽ thành các dải ngang mượt. Di chuột vào một nút hoặc một dòng chảy để xem con số.

Khi nào nên dùng

  • Dòng chảy có cấu trúc. Thương mại giữa nước xuất khẩu và thị trường, ngân sách từ nguồn đến khoản chi, người dùng đi qua phễu: lượng đến từ đâu, đi về đâu, tách nhập ra sao trên đường đi.
  • Tìm tuyến chủ đạo và chỗ rò rỉ. Độ dày của dải chính là giá trị, nên tuyến lớn và những thất thoát nhỏ đều hiện rõ tức thì: góc nhìn kiểm toán cho mọi hệ thống.
  • Chỉ có một chặng? Nếu không có gì chảy xuyên qua, biểu đồ cột so sánh xếp hạng các nguồn gọn gàng hơn một Sankey hai cột.

Dữ liệu lớn trên WebGPU Thử nghiệm

renderer="webgpu" tùy chọn của biểu đồ này vẽ các mark trên GPU trong khi trục/nhãn/tooltip vẫn nằm trên SVG; được kiểm soát theo khả năng phần cứng với tự động chuyển về canvas.

⚗️ Experimental - not yet stable. WebGPU rendering is an opt-in preview. It needs a WebGPU-capable browser (Chrome / Edge, or Safari 26+); everywhere else it falls back to canvas automatically. Axes, labels and tooltips stay on the SVG layer - only the data marks are painted on the GPU.
Heavy-data demo · ~150 liên kết… detecting

Xem dữ liệu chạy theo năm

Gắn date cho từng liên kết rồi bật timeline: snapshot của một năm là các liên kết chia sẻ date đó - các nút dùng chung qua mọi năm, chỉ có dòng chảy đến rồi đi - và độ dày dải tự biến hình mượt giữa các năm. Mặc định tắt - không bật thì biểu đồ giữ nguyên. Đây là kiểu chạy từng năm có tương tác, không phải hiệu ứng vào cảnh một lần bên dưới.

Bấm nút play dưới biểu đồ: dữ liệu chạy qua từng năm, mỗi lần một snapshot. Kéo thanh tua để nhảy đến năm bất kỳ.

tsx
const ref = useRef<SankeyChartHandle>(null);

<SankeyChart ref={ref} {...props} timeline={{ speedMs: 1000, loop: true }} />;
// ref.current?.timeline() -> play() / pause() / seek(year) / stepForward()
vue
<SankeyChart :options="{ ...props, timeline: { speedMs: 1000, loop: true } }" />
svelte
<div use:sankeyChart={{ ...props, timeline: { speedMs: 1000, loop: true } }}></div>
ts
applySankeyChartProps(this.c.nativeElement, { ...props, timeline: { speedMs: 1000, loop: true } });
html
<michi-vz-sankey-chart id="c"></michi-vz-sankey-chart>
<script>
  const el = document.getElementById("c");
  el.timeline = { speedMs: 1000, loop: true };
  // el.getTimeline() -> play() / pause() / seek(year)
</script>
  • speedMs chỉnh nhịp chạy, loop quay vòng, autoplay: true tự chạy khi mount, showControl: false ẩn thanh điều khiển có sẵn.
  • Giá trị trượt mượt giữa các giai đoạn theo mặc định (interpolate); chỉnh chuyển động bằng tweenMseasing, hoặc đặt interpolate: false để cắt thẳng. Khi bật reduced motion, biểu đồ luôn cắt thẳng.
  • Controller headless luôn sẵn sàng: chart.timeline() cho play() / pause() / toggle() / seek(period) / stepForward() / stepBack(), kèm onStepformatPeriod trong config khi cần tự dựng UI.
  • Liên kết không có date vẫn hiển thị ở mọi giai đoạn.
  • timeline thắng progressiveDraw khi cả hai cùng đặt - hiệu ứng vẽ dần bên dưới đứng yên khi timeline đang điều khiển.

Hiệu ứng vẽ dần

Biểu đồ tự vẽ dần từ trái sang phải ngay khi mount, hiện lần lượt các nét vẽ trước khi ổn định vào vị trí. Mặc định tắt - không bật thì biểu đồ giữ nguyên như cũ.

Mỗi đường lớn dần từ năm đầu đến năm cuối; nhãn bám theo ngọn đường rồi dừng ở điểm cuối. Khi hệ điều hành bật reduced motion, biểu đồ hiển thị đầy đủ ngay lập tức.

progressiveDraw: true dùng cấu hình mặc định (1200 ms, easeInOutCubic). Truyền object để tinh chỉnh:

tsx
const ref = useRef<SankeyChartHandle>(null);

<SankeyChart
  ref={ref}
  {...props}
  progressiveDraw={{ durationMs: 2000 }}
/>;
// ref.current?.replay() chạy lại hiệu ứng khi cần
vue
<SankeyChart :options="{ ...props, progressiveDraw: { durationMs: 2000 } }" />
svelte
<div use:sankeyChart={{ ...props, progressiveDraw: { durationMs: 2000 } }}></div>
ts
applySankeyChartProps(this.c.nativeElement, {
  ...props,
  progressiveDraw: { durationMs: 2000 },
});
html
<michi-vz-sankey-chart id="c"></michi-vz-sankey-chart>
<script>
  const el = document.getElementById("c");
  el.progressiveDraw = { durationMs: 2000 };
  // el.replay() chạy lại hiệu ứng
</script>
  • durationMseasing ("linear", "easeOutQuad", "easeInOutCubic", hoặc hàm (t) => t tự viết) quyết định nhịp vẽ.
  • autoplay: false hiển thị biểu đồ vẽ sẵn đầy đủ; gọi replay() (ref handle bên React, method của web component, hoặc instance của core) để chạy hiệu ứng khi cần. replayOnUpdate: true chạy lại mỗi lần dữ liệu thay đổi.
  • Tôn trọng prefers-reduced-motion: biểu đồ hiển thị đầy đủ ngay, không animation.
  • Hiệu ứng vẽ dần chỉ chạy một lần khi mount; mục xem dữ liệu chạy theo năm ở trên chạy từng năm một theo yêu cầu.

Cách dùng

tsx
import { SankeyChart } from "@michi-vz/react";

export default () => <SankeyChart {...props} />; // props = the chart options
vue
<script setup>
import { SankeyChart } from "@michi-vz/vue";
</script>

<template>
  <SankeyChart :options="props" />
</template>
svelte
<script>
  import { sankeyChart } from "@michi-vz/svelte";
</script>

<div use:sankeyChart={props}></div>
ts
// main.ts - register the elements once
import "@michi-vz/angular";
import { applySankeyChartProps } from "@michi-vz/angular";

// component (uses CUSTOM_ELEMENTS_SCHEMA)
// template: <michi-vz-sankey-chart #c></michi-vz-sankey-chart>
applySankeyChartProps(this.c.nativeElement, props);
html
<script type="module" src="https://cdn.jsdelivr.net/npm/@michi-vz/wc/dist/michi-vz-wc.bundle.js"></script>

<michi-vz-sankey-chart id="c"></michi-vz-sankey-chart>
<script>
  Object.assign(document.getElementById("c"), props); // nodes, links, …
</script>
ts
import { mountSankeyChart } from "@michi-vz/core";

const chart = mountSankeyChart(el, props);
chart.update(next);
chart.getContext(); // renderer-agnostic, LLM-ready
chart.destroy();

Cấu trúc dữ liệu

Khác với các biểu đồ khác, một Sankey nhận hai mảng: nodes (mỗi nút có một id duy nhất, một labelcolor tùy chọn) và links (sourcetarget theo id, kèm một value).

ts
const props = {
  linkColorMode: "source", // colour links by their source (or "target")
  nodes: [
    { id: "France" }, { id: "Germany" },
    { id: "EU" }, { id: "Asia" },
  ],
  links: [
    { source: "France", target: "EU", value: 40 },
    { source: "France", target: "Asia", value: 22 },
    { source: "Germany", target: "EU", value: 55 },
    { source: "Germany", target: "Asia", value: 35 },
  ],
};

Một liên kết trỏ tới một id nút không xác định (hoặc một nút nằm trong disabledItems) sẽ bị bỏ kèm một datawarning; vô hiệu hóa một nút cũng bỏ luôn các liên kết của nó.

Các tùy chỉnh bố cục

nodeWidth đặt chiều rộng hình chữ nhật của nút, nodePadding khoảng cách dọc giữa các nút trong một cột, và linkOpacity độ trong suốt của các dải. linkColorMode tô màu mỗi dải theo nút source (mặc định) hoặc target của nó. Bản sao a11y và getContext() hiển thị các liên kết dưới dạng bảng "Nguồn → Đích: giá trị" có thể đọc được.

Nút bo tròn. nodeRadius (px, mặc định 2) bo tròn các góc hình chữ nhật của nút - tăng lên để có kiểu viên thuốc, hoặc đặt 0 cho góc vuông. Giá trị này bị giới hạn ở nửa cạnh ngắn hơn của nút, nên không bao giờ làm biến dạng một nút mỏng.

Dòng chảy bo tròn. Các dòng chảy được vẽ dưới dạng dải tô đặc; linkRadius (px, mặc định 2) bo tròn các góc của chúng nơi gặp các nút, tạo kết nối mềm mại hơn (bị giới hạn ở nửa độ dày của dải; 0 = sắc cạnh). linkColorMode tô màu mỗi dòng chảy theo nút source hoặc target của nó, ở mức linkOpacity:

ts
const props = { nodeRadius: 4, linkRadius: 4, /* …nodes, links */ };

API

Các prop được định kiểu là SankeyChartProps trong @michi-vz/core. Dùng chung cho mọi biểu đồ: width, height, margin, colors / colorsMapping, renderer ("svg", "canvas", hoặc "webgpu" thử nghiệm), highlightItems, disabledItems, và các callback on*. onChartDataProcessed / getContext() trả về ChartContext không phụ thuộc bộ dựng. Tham chiếu đầy đủ: API Sankey.