Biểu đồ dải
Cơ cấu
Ai đang tăng và ai đang tụt? Khi thị phần, phân bổ ngân sách, hoặc kết quả bầu cử xáo trộn từ kỳ này sang kỳ khác, các dải nối mỗi cột cho phép bạn theo dõi một danh mục duy nhất khi nó phình ra, thu hẹp lại, và đổi vị trí với các đối thủ.
Biểu đồ ở trên là cùng một engine trên mọi framework - chỉ có mã tích hợp bên dưới là khác nhau.
Khi nào nên dùng
- Thị phần, phân bổ ngân sách, bảng xếp hạng. Khi các nhóm đổi chỗ nhau qua từng kỳ, các dải nối khiến "ai vượt ai, và khi nào" trở thành điều đập vào mắt người đọc trước tiên.
- Trình bày các cú đổi ngôi cho người làm kinh doanh. Mỗi nhóm giữ nguyên màu khi phình ra, co lại và hoán đổi thứ hạng, nên mắt người xem theo được một "đối thủ" xuyên suốt câu chuyện.
- Nếu chẳng có ai đổi chỗ ai, các dải chạy song song và biểu đồ vùng kể cùng câu chuyện tỷ trọng với ít nét vẽ hơn.
Dữ liệu lớn trên WebGPU Thử nghiệm
RibbonChart có renderer="webgpu" tùy chọn, vẽ các dải của nó trên GPU trong khi trục, nhãn và tooltip vẫn nằm trên lớp SVG. Tính năng này được kiểm soát theo khả năng phần cứng: trên trình duyệt không có WebGPU, nó tự động hạ cấp về canvas, và getContext().renderer báo cáo bộ dựng thực sự đã vẽ.
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:
const ref = useRef<RibbonChartHandle>(null);
<RibbonChart
ref={ref}
{...props}
progressiveDraw={{ durationMs: 2000 }}
/>;
// ref.current?.replay() chạy lại hiệu ứng khi cần<RibbonChart :options="{ ...props, progressiveDraw: { durationMs: 2000 } }" /><div use:ribbonChart={{ ...props, progressiveDraw: { durationMs: 2000 } }}></div>applyRibbonChartProps(this.c.nativeElement, {
...props,
progressiveDraw: { durationMs: 2000 },
});<michi-vz-ribbon-chart id="c"></michi-vz-ribbon-chart>
<script>
const el = document.getElementById("c");
el.progressiveDraw = { durationMs: 2000 };
// el.replay() chạy lại hiệu ứng
</script>durationMsvàeasing("linear", "easeOutQuad", "easeInOutCubic", hoặc hàm(t) => ttự viết) quyết định nhịp vẽ.autoplay: falsehiển thị biểu đồ vẽ sẵn đầy đủ; gọireplay()(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: truechạ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.
Xem dữ liệu chạy theo năm
Dữ liệu vốn đã trải dài qua nhiều năm nên không cần gắn thêm gì cả. Bật timeline: nút play và thanh tua riêng của biểu đồ chạy qua các năm đó, mỗi bước các dải ruy băng chỉ vẽ đến năm đang active rồi khi chạy tiếp sẽ nối dài mượt mà thêm ra. Kéo lùi thanh tua thì các dải cũng co lại tương ứng. Hover chỉ soi được phần đã thực sự vẽ ra. Mặc định tắt - không bật thì biểu đồ giữ nguyên.
Bấm nút play dưới biểu đồ: biểu đồ vẽ dần đến từng năm khi chạy qua. Kéo thanh tua để nhảy đến năm bất kỳ.
const ref = useRef<RibbonChartHandle>(null);
<RibbonChart ref={ref} {...props} timeline={{ speedMs: 1000, loop: true }} />;
// ref.current?.timeline() -> play() / pause() / seek(year) / stepForward()<RibbonChart :options="{ ...props, timeline: { speedMs: 1000, loop: true } }" /><div use:ribbonChart={{ ...props, timeline: { speedMs: 1000, loop: true } }}></div>applyRibbonChartProps(this.c.nativeElement, { ...props, timeline: { speedMs: 1000, loop: true } });<michi-vz-ribbon-chart id="c"></michi-vz-ribbon-chart>
<script>
const el = document.getElementById("c");
el.timeline = { speedMs: 1000, loop: true };
// el.getTimeline() -> play() / pause() / seek(year)
</script>speedMschỉnh nhịp chạy,loopquay vòng,autoplay: truetự chạy khi mount,showControl: falseẩn thanh điều khiển có sẵn.- Controller headless luôn sẵn sàng:
chart.timeline()choplay() / pause() / toggle() / seek(period) / stepForward() / stepBack(), kèmonStepvàformatPeriodtrong config khi cần tự dựng UI. - Giá trị trượt mượt giữa các năm theo mặc định (
interpolate); đặtinterpolate: falseđể cắt thẳng. Khi bật reduced motion, biểu đồ luôn cắt thẳng. timelineđược ưu tiên hơnprogressiveDrawkhi cả hai cùng được bật trên một biểu đồ.
Cách dùng
import { RibbonChart } from "@michi-vz/react";
export default () => <RibbonChart {...props} />; // props = the chart options<script setup>
import { RibbonChart } from "@michi-vz/vue";
</script>
<template>
<RibbonChart :options="props" />
</template><script>
import { ribbonChart } from "@michi-vz/svelte";
</script>
<div use:ribbonChart={props}></div>// main.ts - register the elements once
import "@michi-vz/angular";
import { applyRibbonChartProps } from "@michi-vz/angular";
// component (uses CUSTOM_ELEMENTS_SCHEMA)
// template: <michi-vz-ribbon-chart #c></michi-vz-ribbon-chart>
applyRibbonChartProps(this.c.nativeElement, props);<script type="module" src="https://cdn.jsdelivr.net/npm/@michi-vz/wc/dist/michi-vz-wc.bundle.js"></script>
<michi-vz-ribbon-chart id="c"></michi-vz-ribbon-chart>
<script>
Object.assign(document.getElementById("c"), props); // dataSet/series, title, …
</script>import { mountRibbonChart } from "@michi-vz/core";
const chart = mountRibbonChart(el, props);
chart.update(next);
chart.getContext(); // renderer-agnostic, LLM-ready
chart.destroy();API
Các prop được định kiểu là RibbonChartProps 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.
