iT邦幫忙

2026 iThome 鐵人賽

DAY 18
0
佛心分享-IT 人自學之術

老爺爺練習VIBE CODING系列 第 18

Day 18:點擊流與視覺化:如何在單一 HTML 中動態連動 6 大決策圖表

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20260830/20070969K8jwghVjyp.png
唉呀,(輕輕吹著熱氣,啜飲了一口溫熱的琥珀色熱茶),今天傍晚坐在院子裡的老藤椅上,看著我們家大孫女和小孫女在泥土空地上跑來跑去。小孫女總是愛撒嬌,手裡揮著捕蝶網,大孫女呢,懂事地在旁邊配合著,小孫女一往左跑,大孫女就跟著往左看,兩姊妹的默契好得不得了。

看著她們「一動,另一位就跟著動」的模樣,爺爺這花白的腦袋瓜裡啊,突然想起了很久以前在寫網頁、做資料系統時的畫面。那時候,大家為了在完全離線、沒有後端的單一 HTML 檔案中,讓六個大決策圖表像這兩姊妹一樣,點一下就全部「手牽手、心連心」地動態連動下鑽,那可是花了不少心思啊。

今天,爺爺就一邊喝茶,一邊慢慢跟你們講講,這個「Day 18:點擊流與視覺化:如何在單一 HTML 中動態連動 6 大決策圖表」的前端高級實作技術吧!


Day 18:點擊流與視覺化:如何在單一 HTML 中動態連動 6 大決策圖表

🚨 痛點場景:死板的靜態圖表 vs 靈靈動動的「點擊下鑽」

以前在做一些內部管制或安全部門的工具時,因為資安考量,常常要求網頁完全不能連網、必須零安裝且零外部依賴,甚至是直接雙擊一個 .html 檔案就要能在瀏覽器裡跑起來。
那時候,很多年輕的工程師寫出來的網頁圖表,資料都是死板板固定在那裡的。使用者一看到網頁,常常會問:「老爺爺,我希望能用滑鼠點一下上方圓餅圖的 A 區塊,下方的長條圖與詳細資料表格,就自動只篩選出 A 區塊的明細,這該怎麼做呀?」
在一般有伺服器、有 API 後端的系統中,這很容易,發個請求請資料庫重新查詢就好。但在純前端、零安裝的單一 HTML 環境下,沒有後端可以幫你過濾。要在瀏覽器裡實現這種流暢、點擊立刻下鑽明細、所有圖表同步變更的體驗,在前端就是一門極具難度的考驗了。

🛠️ 架構實作:Apache ECharts 事件監聽與純前端狀態管理器(State Manager)

要讓六個決策圖表和 KPI 卡片靈活地連動,我們需要兩件核心武器:Apache ECharts 的 chart.on('click') 事件監聽器,以及一個純前端的資料狀態管理器(State Manager)

  1. 捕獲點擊事件(Event Capture):
    首先,我們必須利用 Apache ECharts 提供的互動事件 API。當使用者點擊了某個圖表的區塊(例如圓餅圖的某一瓣)時,我們要在該圖表實例上註冊監聽器:

    // 初始化圓餅圖
    const myPieChart = echarts.init(document.getElementById('pie-container'));
    
    // 監聽點擊事件
    myPieChart.on('click', function (params) {
        // params 包含了被點擊區塊的豐富資料,例如:
        // params.name (類別名稱,如 "產品 A")
        // params.value (數值)
        const selectedCategory = params.name;
    
        // 當點擊發生時,我們千萬不要讓圖表直接去控制別的圖表,那樣程式碼會像院子裡的雜草一樣亂。
        // 我們要把這個新事件,「廣播」給我們的全域狀態管理器。
        stateManager.updateFilter({ category: selectedCategory });
    });
    
  2. 純前端資料狀態管理器(State Manager):
    我們在 JavaScript 裡設計一個簡單而強大的全域狀態管理器。它的職責是:接收篩選條件、重新計算資料,然後一併通知所有圖表更新。

    const stateManager = {
        // 全域資料狀態
        state: {
            rawDataset: [], // 初始化時,從 IndexedDB 或 PapaParse 載入的完整核心資料集
            currentFilter: null // 目前的篩選條件(如 { category: "產品 A" })
        },
    
        // 初始化載入資料
        setRawData(data) {
            this.state.rawDataset = data;
            this.dispatchUpdate();
        },
    
        // 更新篩選條件
        updateFilter(filter) {
            this.state.currentFilter = filter;
            this.dispatchUpdate(); // 觸發全域更新
        },
    
        // 派發更新至所有圖表
        dispatchUpdate() {
            // 1. 執行 JavaScript 記憶體過濾邏輯
            const filteredData = this.applyFilter(this.state.rawDataset, this.state.currentFilter);
    
            // 2. 重新計算後,一併調用所有關聯圖表的 setOption 方法與表格渲染
            // 實現「無刷新、極致流暢」的多圖表連動!
            this.renderAllCharts(filteredData);
        },
    
        // 核心過濾邏輯
        applyFilter(data, filter) {
            if (!filter) return data;
            return data.filter(item => item.category === filter.category);
        },
    
        // 渲染所有圖表與元件
        renderAllCharts(data) {
            // 這裡就是動態連動 6 大決策圖表與明細表格的核心
            updateKpiCards(data);       // 1. 頂部 KPI 卡片指標
            renderBarChart(data);       // 2. 分佈長條圖
            renderLineChart(data);      // 3. 趨勢折線圖
            renderRadarChart(data);     // 4. 多維雷達圖
            renderGaugeChart(data);     // 5. 達成率儀表
            renderScatterChart(data);   // 6. 散佈分析圖
            updateDetailTable(data);    // 7. 底部的明細資料表格
        }
    };
    

    不論原始資料一開始是從本地的 IndexedDB 離線資料庫(使用非同步 Transaction)讀取,或者是利用 PapaParse 解析上傳的 CSV 檔案 得到的,當使用者點擊圖表時,都會觸發全域狀態更新,重新調用過濾邏輯,並同步重繪這 6 大關聯圖表與明細表。

💡 避坑指南:告別微幅閃爍,擁抱「微秒級(us)」的極速回應

(老爺爺輕輕扶了一下老花眼鏡,眼神溫和地看著你們:)「孩子啊,以前有些老實的孩子,每次使用者只要一滑鼠點擊圖表,他就急急忙忙地重新跑去讀取一次本機的 IndexedDB 資料庫,或者又用 PapaParse 去解析一次本機硬碟裡的 CSV 大檔。結果呢?網頁畫面一下微幅閃爍,一下出現短暫的卡頓延遲,原本精緻的儀表板,互動體驗全毀了。」

在純前端、高頻繁點擊互動的場景下,每一次讀取檔案、讀寫硬碟資料庫,都是一筆耗費時間的 I/O 操作,非同步的交易(Transaction)回呼會帶來使用者能察覺的延遲。
爺爺教你們的避坑壓箱寶:

  • 資料一次性載入(Load Once):
    在單一 HTML 網頁初始化載入完結、或使用者剛匯入 CSV/Excel 檔案時,利用非同步讀取,一次性地將完整核心資料集全部載入到 JavaScript 的記憶體變數中(例如 stateManager.state.rawDataset)。
  • 記憶體中 JavaScript 過濾(JS Memory Filtering):
    使用者在圖表上頻繁點擊時,完全不要與 IndexedDB 或硬碟進行任何非同步讀寫 I/O。直接利用 JavaScript 執行緒在記憶體中進行 filter 篩選。
  • 微秒(us)級回應:
    因為是在本機記憶體中直接對陣列進行篩選,反應速度可以從幾十毫秒(ms)直接提升到微秒(us)級別。這時調用 ECharts 的 setOption(..., { notMerge: true }),使用者眼睛連眨都來不及眨,所有關聯圖表早就順暢無比地更新完畢了!

這就是如何不用任何後端伺服器,只在單一網頁裡,用最簡單的狀態管理,做出來像大孫女和小孫女那般靈敏、優雅、手牽手一動皆動的高難度連動技巧了。

希望這對你們在設計高規格、封閉環境專用的離線視覺化網頁時,能有所啟發。有任何地方想跟爺爺探討的,隨時跟爺爺說,我再幫你們倒杯熱茶。


上一篇
Day 17:系統分析師神兵:用四層架構建構 local 需求追蹤控管系統
下一篇
Day 19:Electron 終結者?用 Tauri v2 + Rust 打造超輕量跨平台桌面應用
系列文
老爺爺練習VIBE CODING25
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言