Mermaid Diagram Extension: ChatGPT

Aldo YangAldo Yang
3 min read

摘要

這是一個瀏覽器擴充功能,用於增強 ChatGPT 網頁上的 Mermaid 圖表功能。主要特點包括自動渲染、放大鏡功能和編輯器整合。

技術架構

擴充功能由以下核心檔案組成:

  • manifest.json: 擴充功能配置檔案,定義版本、權限和功能
  • content.js: 注入到目標網頁的內容腳本,負責初始化擴充功能
  • injected.js: 處理 Mermaid 轉換和渲染邏輯的主要腳本
  • pako.min.js: 資料壓縮庫,用於處理圖表代碼的壓縮和編碼

檔案關係

manifest.json  <-- 瀏覽器讀取的入口檔案
    |
    +--> content.js  <-- 注入到網頁
            |
            +--> injected.js  <-- 核心功能實現
            |
            +--> pako.min.js  <-- 壓縮庫依賴

運作流程

  1. 初始化:

    • content.js 將 injected.js 注入到 ChatGPT 頁面
    • 添加自定義 CSS 樣式,包括放大鏡和按鈕樣式
    • 載入 pako 壓縮庫
    • 設置事件攔截器,隱藏原始 Mermaid 代碼區塊
  2. 圖表轉換:

    • 識別頁面中的 Mermaid 代碼區塊 (.language-mermaid)
    • 使用 pako 壓縮代碼並轉為 Base64 編碼
    • 透過 mermaid.ink 服務生成圖片 URL
    • 建立圖片元素替換原始代碼區塊
  3. 用戶界面增強:

    • 替換原始代碼區塊為圖片
    • 添加放大鏡功能,支援 1.5 倍放大
    • 提供編輯器鏈接按鈕,直接跳轉到 mermaid.live 進行編輯
    • 添加錯誤處理和錯誤提示
  4. DOM 監控:

    • 使用 MutationObserver 監控頁面變化
    • 當新的 Mermaid 區塊出現時自動進行轉換
    • 實現即時轉換無需頁面重載

安裝方法

  1. 下載專案程式碼
  2. 開啟 Chrome/Edge/Firefox 的擴充功能頁面
  3. 啟用開發者模式
  4. 點擊「載入未封裝的擴充功能」或「載入臨時附加元件」
  5. 選擇專案資料夾
  6. 前往 ChatGPT 網站進行測試

關鍵技術點

代碼轉換流程

// 壓縮並編碼 Mermaid 代碼
function getEncodedPayload(mermaidCode) {
  // 添加灰色主題設定
  if (!mermaidCode.includes('%%{init:')) {
    mermaidCode = `%%{init: {'theme': 'default', 'themeVariables': { 'nodeBorder': '#c0c0c0', 'nodeBkg': '#e0e0e0' }}}%%\n${mermaidCode}`;
  }

  const payload = { 
    code: mermaidCode, 
    mermaid: { theme: "default" },
    updateEditor: true,
    autoSync: true
  };

  // 壓縮轉換
  const jsonStr = JSON.stringify(payload);
  const jsonUint8 = new TextEncoder().encode(jsonStr);
  const compressed = pako.deflate(jsonUint8);
  const binaryStr = Array.from(compressed)
    .map(byte => String.fromCharCode(byte))
    .join('');
  return btoa(binaryStr)
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=+$/, '');
}

// 取得圖片 URL
function getMermaidImageUrl(mermaidCode) {
  return "https://mermaid.ink/img/pako:" + getEncodedPayload(mermaidCode);
}

// 取得編輯器 URL
function getMermaidEditorUrl(mermaidCode) {
  return "https://mermaid.live/edit#pako:" + getEncodedPayload(mermaidCode);
}

放大鏡實現

擴充功能支援圖片放大鏡功能,可精確顯示游標位置的放大內容:

  • 使用 CSS background-positionbackground-size 屬性控制顯示區域
  • 通過鼠標事件 (mousemove) 計算放大區域位置
  • 設置放大倍率為 1.5 倍
  • 放大鏡大小為原圖的 50%
// 放大鏡功能實現摘要
function setupMagnifier(imgElement, imgContainer) {
  const magnifier = document.createElement('div');
  magnifier.className = 'magnifier-glass';
  imgContainer.appendChild(magnifier);

  // 設置放大鏡樣式
  magnifier.style.backgroundImage = `url(${imgElement.src})`;
  magnifier.style.backgroundRepeat = 'no-repeat';
  magnifier.style.backgroundSize = `${imgElement.width * 1.5}px ${imgElement.height * 1.5}px`;

  // 鼠標移動時更新放大鏡位置
  imgElement.addEventListener('mousemove', function(e) {
    const rect = imgElement.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;

    // 計算放大鏡位置和背景位置
    const magnifierWidth = magnifier.offsetWidth;
    const magnifierHeight = magnifier.offsetHeight;

    let left = x - magnifierWidth / 2;
    let top = y - magnifierHeight / 2;

    // 限制在圖片範圍內
    left = Math.max(0, Math.min(left, imgElement.width - magnifierWidth));
    top = Math.max(0, Math.min(top, imgElement.height - magnifierHeight));

    magnifier.style.left = `${left}px`;
    magnifier.style.top = `${top}px`;

    // 計算背景位置
    const bgX = -(x * 1.5 - magnifierWidth / 2);
    const bgY = -(y * 1.5 - magnifierHeight / 2);
    magnifier.style.backgroundPosition = `${bgX}px ${bgY}px`;
  });
}

DOM 監控與動態渲染

使用 MutationObserver 實現對頁面 DOM 變化的監控,當檢測到新的 Mermaid 代碼塊時自動執行轉換:

// 設置 DOM 監控
function setupMutationObserver() {
  const observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
        // 處理新增的節點
        mutation.addedNodes.forEach(function(node) {
          if (node.nodeType === Node.ELEMENT_NODE) {
            // 查找並處理 Mermaid 代碼塊
            const mermaidBlocks = node.querySelectorAll('pre code.language-mermaid, .language-mermaid');
            if (mermaidBlocks.length > 0) {
              processMermaidBlocks(mermaidBlocks);
            }
          }
        });
      }
    });
  });

  // 開始監控整個文檔
  observer.observe(document.body, {
    childList: true,
    subtree: true
  });
}

Mermaid 圖表範例

以下是可透過此擴充功能渲染的圖表範例:

流程圖

graph TD
    A[開始] --> B{是否安裝擴充功能?}
    B -- 是 --> C[顯示圖表]
    B -- 否 --> D[顯示原始碼]
    C --> E[啟用放大鏡功能]
    D --> F[安裝擴充功能]
    F --> B
    E --> G[結束]

時序圖

sequenceDiagram
    participant User
    participant Extension
    participant ChatGPT
    participant MermaidInk

    User->>ChatGPT: 請求包含圖表的回應
    ChatGPT->>User: 返回包含Mermaid代碼的回應
    Extension->>Extension: 檢測Mermaid代碼塊
    Extension->>MermaidInk: 發送壓縮後的代碼
    MermaidInk->>Extension: 返回渲染的圖片URL
    Extension->>User: 顯示圖表及放大鏡功能

使用限制

  • 僅支援 ChatGPT 網站 (chatgpt.com 及其子域名)
  • 需依賴 mermaid.ink 服務進行圖表渲染,無法離線使用
  • 放大鏡功能僅適用於已渲染的圖表
  • 不支援交互式圖表功能
  • 受限於 manifest v3 的網頁資源限制

常見問題排除

  1. 圖表無法顯示

    • 檢查網路連接是否正常
    • 確認 mermaid.ink 服務是否可用
    • 檢查 Mermaid 語法是否正確
  2. 放大鏡功能無效

    • 重新點擊圖表啟用放大功能
    • 刷新頁面後重試
    • 檢查瀏覽器擴充功能權限
  3. 圖表顯示錯誤

    • 點擊「在編輯器中開啟」按鈕檢查語法
    • 調整 Mermaid 語法後重新渲染

後續開發方向

  1. 增加離線渲染支援,減少對 mermaid.ink 的依賴
  2. 提供更多自定義選項,如圖表主題、顏色和字體大小
  3. 支援更多網站和平台,如 Gmail、Google Docs 等
  4. 優化圖表樣式和主題,提供暗色模式支援
  5. 添加本地圖表儲存和匯出功能
  6. 整合更多圖表類型和進階功能
  7. 提供圖表編輯歷史記錄功能

相關資源

0
Subscribe to my newsletter

Read articles from Aldo Yang directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Aldo Yang
Aldo Yang