Biểu đồ cột kép (Tornado)
So sánh
Bên nào thắng, và thắng bao nhiêu? Neo hai giá trị đối lập vào một đường trung tâm chung và sự mất cân bằng hiện rõ chỉ trong nháy mắt - trái so với phải, nam so với nữ, trước so với sau. Đây là tháp dân số kinh điển và biểu đồ tornado, nơi cột dài nhất chính là câu chuyện.
- Nam (bên phải, màu đậm)
- Nữ (bên trái, màu nhạt)
Biểu đồ ở trên là cùng một engine trong 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
- Khi sự bất cân xứng chính là câu chuyện. Tháp dân số, nhập khẩu và xuất khẩu, người ủng hộ và người phản đối: hai đại lượng đối nhau trên một trục giữa, bên nào lệch là thấy ngay.
- Báo cáo một trang cho lãnh đạo. Thanh dài nhất và bên nặng hơn truyền đạt thông điệp trước cả khi người xem kịp đọc một con số: lý tưởng khi bạn chỉ có mười giây chú ý.
- Nếu hai giá trị không đối nghịch nhau (năm nay và năm ngoái, mục tiêu và thực tế), hãy giữ cả hai cùng một phía của trục 0 bằng biểu đồ cột so sánh.
Dữ liệu lớn trên WebGPU Thử nghiệm
DualHorizontalBarChart có tùy chọn renderer="webgpu" để vẽ các cột value1/value2 trên GPU trong khi trục, nhãn và tooltip vẫn ở lớp SVG. Tính năng này được kiểm soát theo khả năng: trên trình duyệt không có WebGPU, nó sẽ tự động hạ cấp xuống canvas, và getContext().renderer báo cáo bất kỳ renderer nào thực sự đã vẽ.
Xem dữ liệu chạy theo năm
Gắn date cho từng dòng rồi bật timeline: biểu đồ tornado thành câu chuyện theo từng năm với nút play và thanh tua riêng, mỗi lần hiển thị cán cân trái/phải của một giai đoạn. Mặc định tắt - không bật thì biểu đồ giữ nguyên.
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ỳ.
const ref = useRef<DualHorizontalBarChartHandle>(null);
<DualHorizontalBarChart ref={ref} {...props} timeline={{ speedMs: 1000, loop: true }} />;
// ref.current?.timeline() -> play() / pause() / seek(year) / stepForward()<DualHorizontalBarChart :options="{ ...props, timeline: { speedMs: 1000, loop: true } }" /><div use:dualHorizontalBarChart={{ ...props, timeline: { speedMs: 1000, loop: true } }}></div>applyDualHorizontalBarChartProps(this.c.nativeElement, { ...props, timeline: { speedMs: 1000, loop: true } });<michi-vz-dual-horizontal-bar-chart id="c"></michi-vz-dual-horizontal-bar-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.- Giá trị trượt mượt giữa các giai đoạn theo mặc định (
interpolate); chỉnh chuyển động bằngtweenMsvàeasing, hoặc đặtinterpolate: 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()choplay() / pause() / toggle() / seek(period) / stepForward() / stepBack(), kèmonStepvàformatPeriodtrong config khi cần tự dựng UI. filter(top-N, sắp xếp) vẫn áp dụng bên trong từng giai đoạn, nên "top 5 mỗi năm" chạy được ngay.- Dòng không có
datehiển thị ở mọi giai đoạn.
Cách dùng
import { DualHorizontalBarChart } from "@michi-vz/react";
export default () => <DualHorizontalBarChart {...props} />; // props = the chart options<script setup>
import { DualHorizontalBarChart } from "@michi-vz/vue";
</script>
<template>
<DualHorizontalBarChart :options="props" />
</template><script>
import { dualHorizontalBarChart } from "@michi-vz/svelte";
</script>
<div use:dualHorizontalBarChart={props}></div>// main.ts - register the elements once
import "@michi-vz/angular";
import { applyDualHorizontalBarChartProps } from "@michi-vz/angular";
// component (uses CUSTOM_ELEMENTS_SCHEMA)
// template: <michi-vz-dual-horizontal-bar-chart #c></michi-vz-dual-horizontal-bar-chart>
applyDualHorizontalBarChartProps(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-dual-horizontal-bar-chart id="c"></michi-vz-dual-horizontal-bar-chart>
<script>
Object.assign(document.getElementById("c"), props); // dataSet/series, title, …
</script>import { mountDualHorizontalBarChart } from "@michi-vz/core";
const chart = mountDualHorizontalBarChart(el, props);
chart.update(next);
chart.getContext(); // renderer-agnostic, LLM-ready
chart.destroy();API
Các prop được định kiểu là DualHorizontalBarChartProps 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 độc lập với renderer.
