多媒體程式開發是指整合文字、圖像、音訊、視訊及動畫,透過程式語言實作互動功能的技術領域。其開發重點在於硬體加速、編碼效率以及使用者體驗的流暢度。
| 開發領域 | 常用語言 | 技術框架/工具 |
|---|---|---|
| 網頁多媒體 | JavaScript / TypeScript | HTML5 Canvas, WebGL, Three.js |
| 行動應用/遊戲 | C++ / C# / Swift | Unity, Unreal Engine, Metal |
| 後端影音處理 | Python / Go / C++ | FFmpeg, OpenCV, GStreamer |
注意:在開發涉及大量運算的多媒體程式時,應優先考量硬體解碼(Hardware Decoding)以降低 CPU 負載。
DirectX 是由微軟開發的一系列應用程式介面(API),旨在讓軟體(特別是遊戲)能直接與顯示卡、音效卡等硬體溝通。它是 Windows 平台與 Xbox 主機多媒體開發的核心支柱。
| 版本 | 重要特性 | 適用環境 |
|---|---|---|
| DirectX 11 | 引入曲面細分 (Tessellation) 與多執行緒渲染,穩定性高。 | Windows 7 及以上版本 |
| DirectX 12 | 底層 API(Low-level),大幅降低 CPU 開銷,支援顯卡多核心調度。 | Windows 10 / 11 |
| DirectX 12 Ultimate | 整合光線追蹤 (Ray Tracing)、網格著色器 (Mesh Shaders) 等次世代技術。 | 高階 GPU 與 Xbox Series X/S |
注意:在現代遊戲開發中,開發者通常透過 Unity 或 Unreal Engine 等引擎呼叫 DirectX,而非直接撰寫底層指令,以提高開發效率。
Media Foundation (MF) 是微軟在 Windows Vista 之後推出的多媒體框架,旨在取代舊有的 DirectShow。它採用全新的管線設計,專為高解析度視訊、數位版權管理 (DRM) 以及更高效的硬體加速而優化,是現代 Windows 應用程式處理影音的核心技術。
Media Foundation 將多媒體處理過程拆解為三個主要層級,這種設計提供了極高的控制彈性:
| 特性 | Media Foundation | DirectShow (舊版) |
|---|---|---|
| 高解析度支援 | 原生優化 4K、8K 與 HDR 內容。 | 擴充性有限,處理超高解析度較吃力。 |
| 硬體加速 | 深度整合 DXVA 2.0,效率極高。 | 依賴特定篩選器實作,效能不一。 |
| 內容保護 | 內建 PMP (Protected Media Path) 支援 DRM。 | 缺乏統一的版權保護機制。 |
| 執行緒模型 | 採用非同步拓撲,減少 UI 凍結。 | 同步執行模型,易導致介面卡頓。 |
注意:雖然 Media Foundation 效能優異,但其 API 設計相對複雜且嚴謹,建議開發者搭配微軟提供的 MFTrace 工具進行除錯,以追蹤媒體管線中的事件流。
DirectShow 是基於元件物件模型 (COM) 的多媒體框架,主要用於 Windows 平台上的影音截取與回放。雖然微軟後來推出了 Media Foundation 作為繼任者,但 DirectShow 因其強大的相容性與靈活性,至今仍在工業相機、醫療影像及傳統影音軟體中廣泛使用。
DirectShow 的核心概念是篩選器圖形 (Filter Graph),透過將不同的篩選器連接成鏈結來處理多媒體資料:
| 功能分類 | 說明 |
|---|---|
| 媒體播放 | 支援多種容器格式(如 AVI, WMV, MP4)與編解碼器的整合。 |
| 影像截取 | 提供與 WDM (Windows Driver Model) 設備溝通的標準介面,適用於 USB 相機。 |
| 硬體加速 | 可透過 Video Mixing Renderer (VMR) 或 EVR 利用顯示卡進行硬體加速渲染。 |
| 格式轉換 | 支援即時影音流的重新取樣、裁切以及色彩空間轉換(如 YUV 轉 RGB)。 |
注意:在進行現代化開發時,若不需要支援過舊的系統,微軟建議優先考慮使用 Media Foundation,它在處理高解析度內容與數位版權管理 (DRM) 上更具優勢。
Vulkan 是由 Khronos Group 開發的次世代跨平台圖形與運算 API。與 OpenGL 不同,Vulkan 屬於底層(Low-level)API,旨在提供更直接的硬體控制權,極大化減少驅動程式的額外負擔(Overhead),並提升多核心處理器的利用率。
Vulkan 的設計邏輯要求開發者承擔更多管理責任,以換取極致的效能表現:
| 特性 | Vulkan | OpenGL |
|---|---|---|
| 驅動程式負擔 | 極低,大部分邏輯由開發者實作。 | 較高,驅動程式負責大量背景管理。 |
| 多執行緒支援 | 原生支援並行任務分配。 | 主要依賴單一執行緒。 |
| 開發複雜度 | 極高,程式碼量通常是 OpenGL 的數倍。 | 中等,對初學者較為友好。 |
| 硬體利用率 | 高,可精準控制 GPU 運算與記憶體。 | 中,受限於 API 的抽象層級。 |
注意:由於 Vulkan 的開發門檻極高,通常建議用於需要極致效能的 3D 遊戲引擎核心(如 id Tech 7)或需要跨平台高效能運算的科學模擬程式。
OpenCV (Open Source Computer Vision Library) 是一個開源的計算機視覺與機器學習軟件庫,用於即時影像處理與分析。
# 讀取影像並顯示
import cv2
image = cv2.imread("image.jpg")
cv2.imshow("Image", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
在 OpenCV 中,讀取影像最核心的函式是 cv::imread。它會將影像檔案載入為 cv::Mat 矩陣格式。
#include <opencv2/opencv.hpp>
// 語法原型
cv::Mat img = cv::imread(const std::string& filename, int flags = cv::IMREAD_COLOR);
常用的標籤 (Flags):
重要觀念:cv::imread 失敗時並不會拋出 C++ 異常,因此傳統的 try-catch 對其無效。當讀取失敗(如路徑錯誤、格式不支援或權限不足)時,它會返回一個空的 cv::Mat 物件。
正確的處理流程應使用 empty() 成員函式進行檢查:
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
std::string path = "data/image.jpg";
cv::Mat img = cv::imread(path);
// 必須檢查影像是否成功載入
if (img.empty()) {
std::cerr << "錯誤:無法讀取影像檔案!" << std::endl;
std::cerr << "請確認路徑是否正確:" << path << std::endl;
return -1;
}
// 讀取成功後才執行操作
std::cout << "影像寬度: " << img.cols << " 高度: " << img.rows << std::endl;
return 0;
}
如果 img.empty() 為真,通常是由以下原因導致:
| 原因 | 說明與對策 |
|---|---|
| 檔案路徑錯誤 | 最常見原因。請檢查相對路徑是否相對於執行檔目錄,或使用絕對路徑。 |
| 不支援的副檔名 | OpenCV 需對應解碼器(如 libjpeg, libpng)。若編譯 OpenCV 時未加入支援,則無法讀取。 |
| 中文路徑問題 | 在 Windows 環境下,舊版或特定編譯環境的 cv::imread 對中文路徑支援不佳。 |
| 權限不足 | 執行程式的使用者沒有讀取該檔案的作業系統權限。 |
若遇到 Windows 中文路徑導致讀取失敗,建議先將檔案讀入記憶體 Buffer,再透過 cv::imdecode 進行解碼:
#include <fstream>
#include <vector>
cv::Mat imread_unicode(std::string path) {
std::ifstream fs(path, std::ios::binary | std::ios::ate);
if (!fs.is_open()) return cv::Mat();
std::streamsize size = fs.tellg();
fs.seekg(0, std::ios::beg);
std::vector<char> buffer(size);
if (fs.read(buffer.data(), size)) {
return cv::imdecode(cv::Mat(buffer), cv::IMREAD_COLOR);
}
return cv::Mat();
}
當點群(如螺絲邊緣或正弦波)的順序混亂時,必須先將其投影至擬合直線的方向上進行排序,隨後才能根據點相對於直線的正負偏移量(Signed Distance)進行正確的分群。以下是整合 OpenCV 與標準 C++ 的實作方案。
首先實作你要求的指定點距離排序功能。這可用於定位起始點或特定特徵點。
#include <vector>
#include <array>
#include <algorithm>
#include <opencv2/opencv.hpp>
using Point2D = std::array<float, 2>;
using Points = std::vector<Point2D>;
namespace GeometryPointsUtil {
bool FindSortedPointsByDistOfPoint(Points& retPoints, const Points& allPoints, const Point2D& aPoint) {
if (allPoints.empty()) return false;
retPoints = allPoints;
std::sort(retPoints.begin(), retPoints.end(), [&aPoint](const Point2D& p1, const Point2D& p2) {
float dx1 = p1[0] - aPoint[0];
float dy1 = p1[1] - aPoint[1];
float dx2 = p2[0] - aPoint[0];
float dy2 = p2[1] - aPoint[1];
// 使用平方和比較以避免 sqrt 運算開銷
return (dx1 * dx1 + dy1 * dy1) < (dx2 * dx2 + dy2 * dy2);
});
return true;
}
}
針對震盪線條,此函數會自動擬合直線、投影排序,並根據直線兩側進行切分。
std::vector<Points> splitOscillatingPoints(const Points& allPoints) {
if (allPoints.size() < 2) return {allPoints};
// 1. 直線擬合
std::vector<cv::Point2f> cvPts;
for (const auto& p : allPoints) cvPts.push_back({p[0], p[1]});
cv::Vec4f line; // (vx, vy, x0, y0)
cv::fitLine(cvPts, line, cv::DIST_L2, 0, 0.01, 0.01);
float vx = line[0], vy = line[1], x0 = line[2], y0 = line[3];
// 2. 投影排序:確保點是沿著直線方向排列
struct ProjectedPoint {
Point2D original;
float t; // 投影長度
float side; // 到直線的代數距離
};
std::vector<ProjectedPoint> projected;
float nx = -vy; // 法向量 x
float ny = vx; // 法向量 y
for (const auto& p : allPoints) {
float dx = p[0] - x0;
float dy = p[1] - y0;
float t = dx * vx + dy * vy; // 投影到直線上的位移
float s = dx * nx + dy * ny; // 垂直於直線的距離(含正負號)
projected.push_back({p, t, s});
}
std::sort(projected.begin(), projected.end(), [](const ProjectedPoint& a, const ProjectedPoint& b) {
return a.t < b.t;
});
// 3. 根據正負號跳變進行分群
std::vector<Points> segments;
if (projected.empty()) return segments;
Points currentGroup;
bool lastSide = (projected[0].side >= 0);
for (const auto& item : projected) {
bool currentSide = (item.side >= 0);
if (currentSide != lastSide && !currentGroup.empty()) {
segments.push_back(currentGroup);
currentGroup.clear();
}
currentGroup.push_back(item.original);
lastSide = currentSide;
}
if (!currentGroup.empty()) segments.push_back(currentGroup);
return segments;
}
Halcon 是由 MVTec 公司開發的一款強大的工業視覺軟體,專為影像處理和機器視覺應用而設計。
Shotcut 是一款免費且開源的影片編輯軟體,支援多種格式且具有許多強大的編輯工具。其特色包括:
適用平台:Windows、Mac、Linux
OpenShot 是一款易於上手的開源影片編輯工具,功能強大且支持多種格式。其主要特點包括:
適用平台:Windows、Mac、Linux
Blender 是一款知名的開源 3D 建模和動畫軟體,內建功能強大的影片編輯器,適合進行影片剪輯和特效製作。其功能包括:
適用平台:Windows、Mac、Linux
Kdenlive 是 Linux 上廣泛使用的開源影片編輯軟體,也支援 Windows。其主要功能包括:
適用平台:Windows、Mac、Linux
Lightworks 提供免費和付費版本,免費版本具備基本編輯功能。其特色包括:
適用平台:Windows、Mac、Linux
以上這些開源影片編輯軟體提供了強大的功能,適合不同層次的影片編輯需求,從簡單的家庭影片剪輯到專業級的影片製作都可以滿足。
| 軟體名稱 | 大約搜尋量 |
|---|---|
| OpenShot | 110,000 |
| Kdenlive | 90,500 |
| Shotcut | 49,500 |
| Avidemux | 18,100 |
| Losslesscut | 14,800 |
| Blender VSE | 10,000 |
| Natron | 6,600 |
| Cinelerra | 5,400 |
| Pitivi | 3,600 |
| LiVES | 1,600 |
OpenShot 是一款免費且開源的影片編輯器,專案名稱為 OpenShot/openshot-qt,主要基於 Python 和 Qt
開發。該專案旨在提供一個易於使用且功能豐富的影片編輯工具,適合不同水平的使用者。
OpenShot 使用 PyQt 作為圖形用戶界面,並結合 libopenshot (C++ 實現) 來處理影片編輯的核心邏輯。此外,OpenShot 還利用了
FFmpeg 來支援多種格式的解碼與編碼。
OpenShot 適用於需要簡單操作、但功能強大的影片編輯需求的用戶。無論是業餘影片創作者還是教育用途,OpenShot 都提供了靈活的工具和插件,便於進行剪輯和創作。
OpenShot 專案擁有活躍的開源社群,使用者和開發者可以透過 GitHub 貢獻程式碼、報告問題或提交新功能建議。歡迎所有人參與,以協助提升 OpenShot 的功能與穩定性。
使用者可以透過 GitHub 頁面下載源碼,或從 OpenShot 官方網站下載可執行檔。詳細安裝指引和說明文件也可在 GitHub 上找到。
import os
import subprocess
def create_kdenlive_project(project_path, video_path, audio_path, srt_path):
"""
建立一個基礎的 Kdenlive XML 專案檔並匯入素材
"""
# 取得檔案絕對路徑以確保 Kdenlive 能正確讀取
video_abs = os.path.abspath(video_path)
audio_abs = os.path.abspath(audio_path)
srt_abs = os.path.abspath(srt_path)
# 基礎 Kdenlive MLT 結構 (簡化版)
kdenlive_xml = f"""<?xml version="1.0" encoding="UTF-8"?>
<mlt version="7.24.0" title="Auto Generated Project">
<producer id="video_main" resource="{video_abs}"/>
<producer id="audio_main" resource="{audio_abs}"/>
<producer id="subtitle_main" resource="{srt_abs}"/>
<playlist id="main_bin">
<entry producer="video_main"/>
<entry producer="audio_main"/>
<entry producer="subtitle_main"/>
</playlist>
<tractor id="main_timeline">
<multitrack>
<track name="Video Track">
<entry producer="video_main" in="0" out="1000"/>
</track>
<track name="Audio Track">
<entry producer="audio_main" in="0" out="1000"/>
</track>
</multitrack>
</tractor>
</mlt>
"""
with open(project_path, "w", encoding="utf-8") as f:
f.write(kdenlive_xml)
print(f"專案檔已生成:{project_path}")
def open_with_kdenlive(project_path, kdenlive_exe_path):
"""
啟動 Kdenlive 並載入生成的專案
"""
try:
# 使用 subprocess 開啟程式並帶入檔案參數
subprocess.Popen([kdenlive_exe_path, project_path])
print("正在啟動 Kdenlive...")
except Exception as e:
print(f"啟動失敗:{e}")
if __name__ == "__main__":
# 設定檔案路徑
MY_VIDEO = "input_video.mp4"
MY_AUDIO = "output_voice.wav"
MY_SRT = "output_subtitle.srt"
SAVE_PROJECT = "auto_project.kdenlive"
# Kdenlive 執行檔路徑 (Windows 範例,Linux 通常直接用 'kdenlive')
KDENLIVE_PATH = r"C:\Program Files\kdenlive\bin\kdenlive.exe"
# 1. 生成專案檔
create_kdenlive_project(SAVE_PROJECT, MY_VIDEO, MY_AUDIO, MY_SRT)
# 2. 開啟 Kdenlive
open_with_kdenlive(SAVE_PROJECT, KDENLIVE_PATH)
import subprocess
# 定義一個簡易的 MLT XML 結構
# 這段 XML 定義了兩段素材的先後播放順序
mlt_xml_content = """<mlt>
<producer id="clip1" resource="video_part1.mp4" />
<producer id="clip2" resource="video_part2.mp4" />
<playlist id="main_track">
<entry producer="clip1" in="0" out="150" />
<entry producer="clip2" in="0" out="300" />
</playlist>
</mlt>
"""
# 將內容寫入檔案
with open("auto_edit.mlt", "w", encoding="utf-8") as f:
f.write(mlt_xml_content)
def render_video(mlt_file, output_file):
"""
使用 melt 命令行工具直接渲染影片 (無需開啟 GUI)
"""
# melt 是 MLT 的命令行介面工具
command = [
"melt",
mlt_file,
"-consumer", f"avformat:{output_file}",
"acodec=aac", "vcodec=libx264", "preset=fast"
]
try:
print(f"開始背景渲染:{output_file}...")
subprocess.run(command, check=True)
print("渲染完成!")
except FileNotFoundError:
print("錯誤:找不到 melt 執行檔,請確認是否安裝 MLT 框架。")
if __name__ == "__main__":
# 執行渲染
render_video("auto_edit.mlt", "final_result.mp4")
此腳本利用影像辨識定位 UI 元素。在執行前,請先擷取剪映介面中「圖文成片」與「生成影片」按鈕的小圖示,分別儲存為 btn_start.png 與 btn_generate.png 存放在程式碼同目錄下。
請先安裝必要的 Python 函式庫:
pip install pyautogui pyperclip opencv-python
import os
import time
import pyautogui
import pyperclip
# 設定參數
JIANYING_PATH = r"C:\Users\YourName\AppData\Local\JianyingPro\Apps\JianyingPro.exe" # 請更換為你的實際路徑
SCRIPT_FILE = "my_script.txt" # 預先準備好的文稿檔
CONFIDENCE_LEVEL = 0.8 # 影像辨識準確度 (0-1)
def run_automation():
# 1. 讀取文稿內容
if not os.path.exists(SCRIPT_FILE):
print("錯誤:找不到文稿檔案")
return
with open(SCRIPT_FILE, "r", encoding="utf-8") as f:
content = f.read()
# 2. 開啟剪映
print("正在啟動剪映...")
os.startfile(JIANYING_PATH)
time.sleep(8) # 等待軟體完全載入
try:
# 3. 定位並點擊「圖文成片」按鈕
start_btn = pyautogui.locateCenterOnScreen('btn_start.png', confidence=CONFIDENCE_LEVEL)
if start_btn:
pyautogui.click(start_btn)
print("已進入圖文成片介面")
time.sleep(2)
else:
print("無法定位『圖文成片』按鈕")
return
# 4. 處理文稿輸入
pyperclip.copy(content) # 將文稿複製到剪貼簿
pyautogui.click(x=pyautogui.size().width//2, y=pyautogui.size().height//2) # 點擊視窗中心確保聚焦
pyautogui.hotkey('ctrl', 'v')
print("文稿已貼上")
time.sleep(1)
# 5. 定位並點擊「生成影片」
gen_btn = pyautogui.locateCenterOnScreen('btn_generate.png', confidence=CONFIDENCE_LEVEL)
if gen_btn:
pyautogui.click(gen_btn)
print("正在生成專案...")
else:
print("無法定位『生成影片』按鈕")
except Exception as e:
print(f"發生錯誤: {e}")
if __name__ == "__main__":
run_automation()
| 步驟 | 說明 |
|---|---|
| 影像擷取 | 擷取圖片時,盡量只擷取按鈕中央的文字或圖示,避免包含過多背景色,以增加不同佈景主題下的相容性。 |
| Time Sleep | 自動化中最常失敗的原因是「軟體還沒反應,程式就點了」。請根據電腦效能調整 time.sleep 的數值。 |
| Fail-Safe | PyAutoGUI 內建保護機制:將滑鼠快速移至螢幕「左上角」可立即中止程式運行。 |
.png 圖示,因為螢幕解析度或縮放率(DPI)改變會導致辨識失敗。pygetwindow 函式庫強制將剪映視窗設為前台活動視窗。注意:頻繁的 UI 自動化可能會因為軟體更新(介面位置改變)而失效。若需長期穩定運行,研究「路徑二:修改 JSON 草稿」會是更健壯的方案。
ffmpeg、ffprobe、ffplayffmpeg -i input.avi output.mp4ffmpeg -ss 00:00:10 -i input.mp4 -t 5 output.mp4ffmpeg -i input.mp4 -q:a 0 -map a output.mp3ffmpeg -i input.mp4 -vf subtitles=sub.srt output.mp4在多媒體開發中,確保執行環境具備 FFmpeg 是基本需求。透過 Python 的 subprocess 模組與 urllib,我們可以實作自動化的環境配置流程。
程式碼主要分為兩個階段:偵測系統路徑與遠端下載解壓縮。
shutil.which() 尋找執行檔,這是跨平台最穩定偵測 PATH 的方式。sys.platform 決定下載連結(Windows 通常下載 .zip,Linux 下載 .tar.xz)。os.environ["PATH"]。
import os
import shutil
import platform
import urllib.request
import zipfile
def ensure_ffmpeg():
# 1. 檢查系統 PATH 是否已有 ffmpeg
if shutil.which("ffmpeg"):
print("FFmpeg 已存在於系統路徑中。")
return True
print("未偵測到 FFmpeg,準備開始下載...")
# 2. 根據作業系統設定下載資訊 (以 Windows 為例)
if platform.system() == "Windows":
url = "https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip"
target_zip = "ffmpeg.zip"
extract_dir = "ffmpeg_bin"
# 下載檔案
urllib.request.urlretrieve(url, target_zip)
# 解壓縮
with zipfile.ZipFile(target_zip, 'r') as zip_ref:
zip_ref.extractall(extract_dir)
# 尋找解壓後的 bin 目錄並加入環境變數
# 實際路徑需視壓縮包結構而定
ffmpeg_path = os.path.abspath(os.path.join(extract_dir, "ffmpeg-release-essentials", "bin"))
os.environ["PATH"] += os.pathsep + ffmpeg_path
print(f"FFmpeg 已部署至: {ffmpeg_path}")
return True
else:
print("目前範例僅支援 Windows 自動下載,其餘系統請手動安裝。")
return False
# 執行檢查
ensure_ffmpeg()
| 項目 | 說明 |
|---|---|
| 權限問題 | 在 Linux 或 macOS 下,下載後的二進位檔可能需要透過 os.chmod(path, 0o755) 賦予執行權限。 |
| 版本鎖定 | 建議從可靠的來源(如 Gyan.dev 或 BtbN)下載,並確認版本與你的程式碼相容。 |
| 網路超時 | FFmpeg 體積較大,下載時建議加入 try-except 處理網路中斷,或使用 requests 庫顯示進度條。 |
AppData 或專案根目錄,避免重複下載。注意:在生產環境中,頻繁地下載大型二進位檔可能會影響使用者體驗。建議在第一次啟動時提示用戶,或在安裝包中預載。
在 Python 中進行螢幕錄影,最常見且穩定的做法是結合 PyAutoGUI(用於擷取畫面)、OpenCV(用於編碼與儲存影片)以及 NumPy(用於處理影像數據)。
首先需要安裝必要的套件。打開終端機並執行以下指令:
pip install opencv-python pyautogui numpy
下方程式碼會擷取全螢幕畫面,並將其儲存為 output.mp4 檔案。按下鍵盤上的 q 鍵即可停止錄影。
import cv2
import pyautogui
import numpy as np
# 取得螢幕解析度
SCREEN_SIZE = tuple(pyautogui.size())
# 定義影片編碼格式 (FourCC)
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
# 建立 VideoWriter 物件 (檔名, 編碼, 幀率, 解析度)
out = cv2.VideoWriter("output.mp4", fourcc, 20.0, SCREEN_SIZE)
print("錄影中... 按下 'q' 鍵停止。")
try:
while True:
# 擷取螢幕畫面
img = pyautogui.screenshot()
# 轉換為 NumPy 陣列
frame = np.array(img)
# 將顏色從 RGB 轉換為 BGR (OpenCV 標準格式)
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
# 寫入影格到影片檔案
out.write(frame)
# 顯示錄影預覽 (選用)
# cv2.imshow("Preview", frame)
# 檢測鍵盤輸入
if cv2.waitKey(1) == ord("q"):
break
finally:
# 釋放資源並關閉視窗
out.release()
cv2.destroyAllWindows()
print("錄影結束,檔案已儲存。")
| 問題現象 | 原因與建議 |
|---|---|
| 影片播放速度太快 | 實際錄製的 FPS 低於設定值。應調低寫入的 FPS,或改用更高效的擷取庫如 mss。 |
| 顏色不正常 | 忘記進行 COLOR_RGB2BGR 轉換。 |
| 程式碼執行時卡頓 | 擷取高解析度螢幕非常耗費 CPU,建議降低螢幕解析度或僅錄製特定區域。 |
Manim(Mathematical Animation Engine)是一個用 Python 編寫的動畫庫,特別用來創建數學圖像和動畫。Manim 可以用於生成高品質的動畫,展示數學概念、代碼運行過程,或者任何以圖像和動畫表現的東西。
Manim 的動畫一般是通過編寫 Python 腳本來完成的,然後生成視頻文件。每個動畫通常包含一個或多個場景 (Scene),而每個場景則由不同的對象 (Mobject) 組成。
from manim import *
class MyFirstScene(Scene):
def construct(self):
text = Text("Hello, Manim!") # 創建一個文字對象
self.play(Write(text)) # 生成動畫
可以通過 pip 安裝 Manim:
pip install manim
OpenGL (Open Graphics Library) 是一個跨語言、跨平台的應用程式介面 (API),用於渲染 2D 與 3D 向量圖形。它由 Khronos Group 維護,廣泛應用於電腦輔助設計 (CAD)、虛擬實境、科學視覺化以及電子遊戲開發。
OpenGL 採用管線 (Pipeline) 架構,將 3D 數據轉換為螢幕上的像素。現代 OpenGL 核心模式高度依賴著色器 (Shaders):
| 特性 | 說明 |
|---|---|
| 跨平台相容性 | 可在 Windows、Linux、macOS (透過轉譯層) 及行動裝置 (OpenGL ES) 上執行。 |
| 狀態機模型 | OpenGL 運作如同一個巨大的狀態機,開發者設定狀態(如當前顏色、綁定的貼圖)後執行繪圖指令。 |
| GLSL 語言 | 使用類 C 語言的 OpenGL Shading Language 撰寫 GPU 程式,具備強大的運算能力。 |
| 擴展機制 | 允許硬體廠商在不更新 API 標準的情況下,透過 Extension 引入新的顯示卡功能。 |
注意:雖然 Vulkan 已被視為 OpenGL 的繼任者,提供更底層的硬體控制,但 OpenGL 因其相對簡單的進入門檻與豐富的文檔,仍是學習圖學程式開發的首選。
ManimGL 是 Manim 的一個高效變體,用於製作數學動畫,專注於 OpenGL 加速來提高渲染速度。
使用 pip 安裝:
pip install manimgl
或從 GitHub 獲取最新版本:
git clone https://github.com/ManimCommunity/ManimGL.git
cd ManimGL
pip install -e .
使用 ManimGL 渲染一個簡單場景:
from manimlib import *
class HelloManim(Scene):
def construct(self):
text = Text("Hello, ManimGL!")
self.play(Write(text))
self.wait(2)
運行指令:
manimgl script.py HelloManim
如果遇到安裝或運行問題,可嘗試:
pip install --upgrade pipBlender 是一款開源且全能的 3D 創作軟體,涵蓋了從建模、動畫、渲染到合成與影片編輯的完整管線。它以強大的 Cycles 渲染引擎與靈活的 Python API 著稱,是獨立開發者與中小型工作室的核心工具。
Blender 的架構設計極為緊湊,透過多個專用引擎協同工作:
| 特性 | 說明 | |
|---|---|---|
| Python API | 整個 UI 與功能幾乎都能透過 Python 腳本控制,極易開發插件(Add-ons)。 | 原生支援 Windows、macOS (Apple Silicon) 及 Linux,且檔案格式 (.blend) 全平台通用。 |
| 一體化管線 | 內建影片剪輯器 (VSE) 與合成器 (Compositor),無需切換軟體即可完成後期製作。 |
對於需要批量處理 3D 資料或自動化建模的開發者,Blender 提供了強大的後台模式:
blender -b -P script.py,無需開啟圖形介面即可進行自動化任務。注意:Blender 更新速度極快(約每三個月一個版本),開發腳本時需注意不同版本間 API 的相容性變化。
bpy 模組是一個專門為 Blender 設計的 Python API,允許使用者在 Blender 內透過程式碼來創建、修改以及管理 3D 圖像和動畫。
bpy?bpy 是 Blender Python 的縮寫,它是一組函數庫,允許使用 Python 腳本來操作 Blender 的核心功能。透過 bpy,使用者可以:
bpy 的主要模組和功能bpy 包含了多個子模組,每個模組都有特定的用途:
bpy.data: 存取 Blender 中的所有數據(如物件、材質、場景等)。bpy.ops: 操作類,執行操作(如移動、旋轉、縮放物件)。bpy.context: 訪問目前的 Blender 狀態(如選中的物件或啟用的工具)。bpy.types: 定義 Blender 中所有的數據結構(如 Mesh、Camera、Material)。bpy.utils: 提供一些輔助功能(如腳本加載和卸載)。以下是使用 bpy 創建立方體的簡單範例:
import bpy
# 刪除現有物件
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False)
# 添加立方體
bpy.ops.mesh.primitive_cube_add(size=2, enter_editmode=False, align='WORLD', location=(0, 0, 0))
bpy?使用 bpy 讓你可以將重複的工作自動化,並且生成複雜的模型、動畫和渲染。對於遊戲設計師、建築師、動畫師等專業人士來說,bpy 提供了強大的工具來優化工作流程。
欲了解更多關於 bpy 模組的細節,請參考官方文件:Blender Python API Documentation
Unity 是一個功能強大的遊戲開發引擎和平臺,專門設計用於創建 2D 和 3D 遊戲、互動應用程式及虛擬現實 (VR) 和增強現實 (AR) 體驗。它提供簡單易用的介面和豐富的工具,適合初學者和專業開發人員使用。
Unity 是一個強大且靈活的開發引擎,為開發者提供了廣泛的應用場景和工具支持。無論是初學者還是專業開發人員,都可以利用 Unity 快速創建高質量的 2D、3D 遊戲及互動應用。
Cocos 是一個全球領先的開源移動遊戲開發框架,包含早期純程式碼驅動的 Cocos2d-x 以及現代化的全功能編輯器 Cocos Creator。它以輕量、高效及跨平台支援著稱,是開發 2D 與 3D 手遊、小遊戲(如微信小遊戲、TikTok 小遊戲)的首選工具。
Cocos 家族主要分為兩個重要的發展階段,滿足不同開發習慣的需求:
| 特性 | 說明 |
|---|---|
| 極致跨平台 | 支援 iOS、Android、Windows、Mac 以及各類 Web 瀏覽器與即時玩小遊戲平台。 |
| 高性能渲染器 | 底層採用自研的 GFX 抽象層,支援多種圖形後端如 Vulkan、Metal、DirectX 與 WebGL。 |
| 輕量化體積 | 引擎核心小巧,封裝後的遊戲啟動速度快,適合網路環境受限或對讀取速度要求高的平台。 |
| TypeScript 支援 | Cocos Creator 深度整合 TypeScript,提供完善的型別檢查與語法提示,降低大型專案維護難度。 |
注意:Cocos Creator 目前已演進至 3.x 版本,完全整合了 2D 與 3D 的核心技術,開發者可在同一個專案中混合製作 2D UI 與 3D 場景。
開發一個語音合成系統通常分為三個階段。首先是前端處理,將原始文本轉化為語言學特徵(如分詞、音標轉換、韻律預測);接著是聲學模型,將這些特徵映射成聲學表示(如梅爾頻譜);最後是聲碼器 (Vocoder),負責將聲學表示還原成人類可聽的波形音頻。
| 類別 | 工具/模型 | 開發特色 |
|---|---|---|
| 開源框架 | Coqui TTS / ESPnet | 模組化設計,支援大量預訓練模型與 Fine-tuning |
| 輕量化引擎 | MeloTTS / Kokoro | CPU 友善,適合邊緣運算或嵌入式設備 |
| 對話優化 | ChatTTS | 專為口語對話設計,支援插入笑聲、口頭禪等細節 |
| 研究級模型 | StyleTTS 2 / VITS | 基於生成對抗網路 (GAN),音質極其接近真人 |
若要開發具備特定音色的 TTS,你需要準備高品質的數據集(通常為 1 到 10 小時的錄音與對應文本)。開發者常使用 Transfer Learning (遷移學習) 技術,在大型基礎模型上進行微調,這能顯著降低數據量需求並提升聲音的相似度與自然度。
對於大多數應用開發者而言,直接調用成熟的雲端 API 是最高效的方案。例如 ElevenLabs API 提供極強的情感表達,Microsoft Azure Speech SDK 提供最完整的 SSML (語音合成標記語言) 支援,讓開發者能透過標籤精準控制停頓、重音與語氣。此外,OpenAI TTS API 則以簡潔的介面與極低的推理延遲深受即時互動應用喜愛。
在開發初期,建議優先考量「延遲度 (RTF)」與「音質」的平衡。若應用於即時客服,低延遲的流式傳輸 (Streaming) 是關鍵;若應用於有聲書,則應優先追求具備長文本處理能力與豐富韻律感的模型。此外,需注意各國語言的 G2P (字元轉音素) 支援情況,這直接決定了發音的正確認識。
CosyVoice 2 是阿里巴巴開源的語音合成(TTS)模型進階版。相比於第一代,它在發音準確性、情感控制細粒度以及流式推理延遲上取得了顯著突破。它不僅支援高品質的音色克隆,更引入了指令可控技術,讓 AI 說話更具「人味」。
CosyVoice 2 採用了「文本-語音語言模型」與「流匹配(Flow Matching)」技術,實現了端到端的語音生成:
| 功能 | CosyVoice 2 說明 |
|---|---|
| 多語言支援 | 支援中、英、日、韓以及多種方言(粵語、四川話、上海話、天津話等)。 |
| 情感/指令控制 | 可透過指令(如「開心地說」、「憤怒地說」)控制語音情緒與語速。 |
| 3 秒極速克隆 | 只需 3 至 10 秒的樣本音訊,即可實現 Zero-shot 高保真音色復刻。 |
| 混合語種合成 | 支援在同一段文字中混合中英多語言,且音色保持高度一致。 |
注意:在本地部署 CosyVoice 2 時,建議配備至少 8GB 顯存的 NVIDIA 顯示卡,並使用官方推薦的 vLLM 加速框架以獲得最佳的 RTF(實時率)表現。
CosyVoice 2 基於 Python 開發,由於涉及複雜的音訊處理與深度學習環境,強烈建議使用 Conda 虛擬環境進行隔離安裝。目前官方針對 Linux 支援度最高,Windows 用戶則建議透過 WSL2 或特定的社群修正版進行部署。
在開始前,請確保您的系統已安裝 NVIDIA 驅動程式(建議顯存 8GB 以上)以及 Conda。
conda create -n cosyvoice2 python=3.10
conda activate cosyvoice2
Pynini 是處理文本規範化的核心組件,必須透過 conda 安裝:
conda install -y -c conda-forge pynini==2.1.5
git clone --recursive https://github.com/FunAudioLLM/CosyVoice.git
cd CosyVoice
pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
CosyVoice 2 需要下載預訓練模型權重。您可以透過 Python 腳本自動下載:
from modelscope import snapshot_download
# 下載 0.5B 主模型
snapshot_download('iic/CosyVoice2-0.5B', local_dir='pretrained_models/CosyVoice2-0.5B')
# 下載文本規範化資源
snapshot_download('iic/CosyVoice-ttsfrd', local_dir='pretrained_models/CosyVoice-ttsfrd')
CosyVoice 2 提供多種模式,滿足從快速配音到專業克隆的需求:
| 使用模式 | 操作說明 | 適用場景 |
|---|---|---|
| 啟動 WebUI | 執行 python webui.py,在瀏覽器開啟可視化介面。 |
手動配音、快速測試效果。 |
| 3秒極速復刻 | 上傳 3-10 秒參考音頻與對應文字,實現音色克隆。 | 個性化語音包、自媒體配音。 |
| 跨語言/方言 | 輸入中文文字,選擇粵語或四川話音色輸出。 | 在地化內容製作。 |
| 指令控制 | 在文字前加上指令(如:[laughter]、[angry])。 | 有聲書、戲劇化配音。 |
如果您想將 CosyVoice 2 整合進自己的 Python 專案(如 Kdenlive 的自動化腳本):
from cosyvoice.cli.cosyvoice import CosyVoice2
import torchaudio
# 初始化模型
cosyvoice = CosyVoice2('pretrained_models/CosyVoice2-0.5B')
# 執行推理 (以預訓練音色為例)
output = cosyvoice.inference_sft('你好,我是人工智慧語音助手。', '中文女')
# 儲存音訊
torchaudio.save('output.wav', output['tts_speech'], cosyvoice.sample_rate)
注意:如果您在 Windows 上安裝遇到 sox 或編譯錯誤,可以參考 GitHub Issue #1046,或嘗試使用一鍵安裝包。
import os
import torch
import torchaudio
import re
from cosyvoice.cli.cosyvoice import CosyVoice
# 初始化 CosyVoice2 模型
# 確保路徑指向包含核心權重與設定檔的資料夾
cosyvoice = CosyVoice('pretrained_models/CosyVoice2-0.5B')
def segment_text(text, limit=80):
"""
依據標點符號將長文章切分為適當長度的片段,避免語音生成中斷或記憶體溢出
"""
# 鎖定中文與英文常見句末標點
pattern = r'([。!?;!\?\n])'
parts = re.split(pattern, text)
chunks = []
current = ""
for i in range(0, len(parts)-1, 2):
sentence = parts[i] + parts[i+1]
if len(current) + len(sentence) <= limit:
current += sentence
else:
if current:
chunks.append(current.strip())
current = sentence
if current:
chunks.append(current.strip())
return [c for c in chunks if c]
def run_tts_pipeline(text, spk_id, file_name):
"""
執行長文本推理並在 Tensor 層級進行音訊合併
"""
text_list = segment_text(text)
combined_tensors = []
print(f"處理中,文章已切分為 {len(text_list)} 個區段")
for idx, segment in enumerate(text_list):
# 呼叫 CosyVoice2 推理介面
# 可切換為 inference_zero_shot 使用參考音頻
result = cosyvoice.inference_sft(segment, spk_id)
combined_tensors.append(result['tts_speech'])
print(f"已完成: {idx + 1}/{len(text_list)}")
if combined_tensors:
# 使用 torch.cat 進行無縫拼接
final_audio = torch.cat(combined_tensors, dim=1)
# 儲存為 wav,建議採樣率為 22050Hz
torchaudio.save(file_name, final_audio, 22050)
print(f"任務成功!檔案儲存至: {file_name}")
if __name__ == "__main__":
long_content = "在此貼入你的長篇文章內容,這段程式碼會自動處理斷句與合併。"
run_tts_pipeline(long_content, '中文女', 'output_v2.wav')
import torch
import torchaudio
import re
from cosyvoice.cli.cosyvoice import CosyVoice
# 初始化 CosyVoice 2
cosyvoice = CosyVoice('pretrained_models/CosyVoice2-0.5B')
def format_srt_time(seconds):
"""將秒數轉換為 SRT 時間格式 HH:MM:SS,mmm"""
milliseconds = int((seconds - int(seconds)) * 1000)
seconds = int(seconds)
minutes, seconds = divmod(seconds, 60)
hours, minutes = divmod(minutes, 60)
return f"{hours:02}:{minutes:02}:{seconds:02},{milliseconds:03}"
def generate_audio_and_srt(full_text, speaker_id, output_wav, output_srt):
# 按標點符號切分長文章
segments = re.split(r'([。!?;!\?\n])', full_text)
chunks = []
for i in range(0, len(segments)-1, 2):
text = (segments[i] + segments[i+1]).strip()
if text: chunks.append(text)
audio_list = []
srt_entries = []
current_time = 0.0
sample_rate = 22050
print(f"開始處理 {len(chunks)} 段文本...")
for i, chunk in enumerate(chunks):
# 推理生成語音張量
output = cosyvoice.inference_sft(chunk, speaker_id)
audio_tensor = output['tts_speech']
audio_list.append(audio_tensor)
# 計算該段音訊持續秒數 (張量長度 / 採樣率)
duration = audio_tensor.shape[1] / sample_rate
end_time = current_time + duration
# 建立 SRT 條目
srt_entries.append(
f"{i+1}\n"
f"{format_srt_time(current_time)} --> {format_srt_time(end_time)}\n"
f"{chunk}\n"
)
current_time = end_time
print(f"已完成第 {i+1} 段對齊")
# 合併並儲存音訊
combined_audio = torch.cat(audio_list, dim=1)
torchaudio.save(output_wav, combined_audio, sample_rate)
# 儲存 SRT 檔案
with open(output_srt, 'w', encoding='utf-8') as f:
f.write("\n".join(srt_entries))
print(f"完成!音訊:{output_wav}, 字幕:{output_srt}")
if __name__ == "__main__":
article = "這是一段長文章範例。[laughter] 我們可以精確地計算每一句說話的時間。這樣匯入 Kdenlive 就會自動對齊了。"
generate_audio_and_srt(article, '中文女', 'output.wav', 'output.srt')
import os
import torch
import torchaudio
import re
from cosyvoice.cli.cosyvoice import CosyVoice
# 初始化模型
cosyvoice = CosyVoice('pretrained_models/CosyVoice2-0.5B')
def segment_text_with_tags(text, limit=100):
"""
切分長文本,同時確保標籤如 [laughter] 不會被切割
"""
# 匹配中文標點符號與換行
pattern = r'([。!?;!\?\n])'
parts = re.split(pattern, text)
chunks = []
current = ""
for i in range(0, len(parts)-1, 2):
sentence = parts[i] + parts[i+1]
if len(current) + len(sentence) <= limit:
current += sentence
else:
if current:
chunks.append(current.strip())
current = sentence
if current:
chunks.append(current.strip())
return chunks
def generate_expressive_audio(text, spk_id, output_path):
"""
生成包含情感指令的長語音
"""
segments = segment_text_with_tags(text)
audio_data = []
for idx, seg in enumerate(segments):
# 使用 instruct 模式以獲得更佳的標籤執行效果
# 若使用 sft 模式亦支援基礎標籤,但 instruct 模式對情感控制更精確
output = cosyvoice.inference_instruct(seg, spk_id, '控制語氣與情感')
audio_data.append(output['tts_speech'])
print(f"處理段落 {idx+1}/{len(segments)}")
if audio_data:
final_wav = torch.cat(audio_data, dim=1)
torchaudio.save(output_path, final_wav, 22050)
print(f"含有情感指令的音訊已儲存:{output_path}")
if __name__ == "__main__":
# 範例:嵌入情感標籤的長文本
rich_text = "這是一個非常棒的消息! [laughter] 我簡直不敢相信這是真的。 [surprise] 但如果事情搞砸了, [angry] 我會非常生氣。"
generate_expressive_audio(rich_text, '中文女', 'expressive_output.wav')
開發 ASR (Automatic Speech Recognition) 系統通常遵循以下核心路徑。首先是音訊預處理(如降噪、VAD 語音活動偵測與特徵提取);接著進入模型推論,將聲學訊號轉化為文字機率;最後透過後處理(如標點符號恢復、逆文字正規化 ITN)產出最終文本。現代開發趨勢已從傳統的 HMM 轉向「端到端 (End-to-End)」神經網路架構,大幅簡化了開發複雜度。
| 類別 | 工具/模型 | 2026 年開發特點 |
|---|---|---|
| 基礎模型 | OpenAI Whisper (V3) | 產業標準,具備極強的抗噪能力與多語種支援,最適合長音檔轉錄。 |
| 即時串流 | NVIDIA Parakeet-TDT | 專為超低延遲設計,支援串流辨識 (Streaming),適合 AI 語音助手。 |
| 國產優化 | FunASR / 雅廷引擎 | 對中文、中英夾雜與台灣口音有深度優化,支援時間戳與發音人辨識。 |
| 部署框架 | Faster-Whisper / Sherpa-ONNX | 大幅提升推論速度並降低記憶體佔用,適合在邊緣設備或本地伺服器運行。 |
在開發 ASR 系統時,需重點監控 CER (字符錯誤率) 以評估準確性。針對即時應用,RTF (即時係數) 與延遲 (Latency) 至關重要,必須確保語音處理速度遠快於說話速度。2026 年的開發重點已轉向「長文本記憶」與「上下文感知」,例如整合 LLM 來修正專業術語或特定行業別的辨識偏見。
若追求快速上線,開發者通常會調用雲端 API。Deepgram 與 AssemblyAI 在 2026 年以低延遲與豐富的 metadata(如情緒偵測、重點摘要)受到青睞。Microsoft Azure Speech SDK 則提供最完整的自定義模型微調 (Custom Speech) 介面,允許開發者上傳特定領域的文本數據,解決醫療、法律等特殊詞彙辨識不準的問題。
對於個人開發者,建議使用 Hugging Face Transformers 庫搭配 PyTorch 進行快速實驗。若應用場景涉及隱私(如醫療記錄),應採用 Whisper.cpp 或 Vosk 進行完全離線的本地部署。若需構建大型語音服務,則建議採用 Triton Inference Server 或 Docker 容器化技術,實現 ASR 模型的高效調度與擴展。
HTML5 的 <canvas> 元素是一個可供使用 JavaScript 繪圖的區域,允許在網頁上呈現 2D 和 3D
圖像。它是一個容器,可以透過程式碼進行繪製操作,如畫線、圖形和圖片,適合遊戲、圖形編輯等需要即時生成的應用。
以下是 canvas 元素的基本語法:
<canvas id="myCanvas" width="500" height="500"></canvas>
要在 canvas 元素上繪製內容,必須使用 getContext 方法。這個方法允許取得繪圖的上下文,目前最常用的選項是 "2d"。它會返回一個
CanvasRenderingContext2D 物件,提供許多繪圖方法。
例如,以下 JavaScript 程式碼可以取得 canvas 的 2D 繪圖上下文:
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
使用 getContext("2d") 獲得的繪圖上下文,能夠進行如畫線、畫矩形、填充顏色等基本繪圖操作。例如:
moveTo(x, y) 和 lineTo(x, y) 方法來定義線段,並使用 stroke()
畫出線條。fillRect(x, y, width, height) 繪製填滿的矩形,或
strokeRect(x, y, width, height) 繪製空心矩形。fillStyle 設定填充顏色,例如 ctx.fillStyle = "blue";範例程式碼:
ctx.fillStyle = "blue";
ctx.fillRect(50, 50, 100, 100); // 畫一個藍色矩形
ctx.strokeStyle = "red";
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(200, 200);
ctx.stroke(); // 畫一條紅色線條
若要清除 canvas 中的圖像,可以使用 clearRect(x, y, width, height) 方法。例如,清除整個畫布的程式碼為:
ctx.clearRect(0, 0, canvas.width, canvas.height);
利用 requestAnimationFrame() 可以實現平滑的動畫效果。透過每次更新畫面前先清除上一幀的內容,可以繪製出動態效果。以下是簡單的動畫範例:
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillRect(x, y, 50, 50); // 繪製方塊
x += 1; // 更新位置
requestAnimationFrame(draw);
}
draw();
Canvas 的尺寸應設定在 HTML 中,若使用 CSS 改變大小可能導致畫面失真。此外,canvas 並非為了代替高解析度的影像,而是用來即時生成和動態繪圖。
style.transform 是 CSS 的屬性之一,可用來對元素進行旋轉、縮放、位移、傾斜等 2D 或 3D 轉換操作。
scale() 則是其中的「縮放」函式,語法為:
transform: scale(sx [, sy]);
其中:
sx:水平方向縮放倍數sy:垂直方向縮放倍數(可省略,省略時等於 sx)
const el = document.getElementById("target");
el.style.transform = "scale(1.5)"; // x與y都放大1.5倍
el.style.transform = "scale(1.5, 0.5)"; // 水平放大1.5倍,垂直縮小為一半
---
scale() 是一種「視覺轉換」,它不會改變元素的實際 DOM 屬性(如 offsetWidth 或 clientWidth),但會改變 getBoundingClientRect() 的回傳值。
el.getBoundingClientRect().width // 會反映 scale 的影響
el.offsetWidth // 原始寬度,不受 scale 影響
---
<style>
#box {
width: 100px;
height: 100px;
background: skyblue;
transition: transform 0.3s;
}
#box:hover {
transform: scale(1.5);
}
</style>
<div id="box"></div>
---
以下範例從 HTML <table> 讀取資料,使用原生 <canvas> API 的 arc() 繪製圓餅圖,不需任何外部套件。
<table id="dataTable" border="1" style="margin:10px auto;">
<tr><th>類別</th><th>數值</th></tr>
<tr><td>蘋果</td><td>30</td></tr>
<tr><td>香蕉</td><td>15</td></tr>
<tr><td>櫻桃</td><td>25</td></tr>
<tr><td>芒果</td><td>20</td></tr>
</table>
<canvas id="pieCanvas" width="400" height="400" style="display:block; margin:auto; border:1px solid #aaa;"></canvas>
---
const table = document.getElementById("dataTable");
const canvas = document.getElementById("pieCanvas");
const ctx = canvas.getContext("2d");
const labels = [];
const values = [];
for (let i = 1; i < table.rows.length; i++) { // 跳過表頭
const row = table.rows[i];
labels.push(row.cells[0].textContent);
values.push(parseFloat(row.cells[1].textContent));
}
// 計算總和
const total = values.reduce((a, b) => a + b, 0);
// 繪製圓餅圖
let startAngle = 0;
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const radius = 120;
// 自動配色
const colors = ["#FF6384", "#36A2EB", "#FFCE56", "#4BC0C0", "#9966FF", "#FF9F40"];
for (let i = 0; i < values.length; i++) {
const sliceAngle = (values[i] / total) * 2 * Math.PI;
const endAngle = startAngle + sliceAngle;
// 畫圓餅區塊
ctx.beginPath();
ctx.moveTo(centerX, centerY);
ctx.arc(centerX, centerY, radius, startAngle, endAngle);
ctx.closePath();
ctx.fillStyle = colors[i % colors.length];
ctx.fill();
// 標示文字
const midAngle = startAngle + sliceAngle / 2;
const textX = centerX + Math.cos(midAngle) * (radius + 20);
const textY = centerY + Math.sin(midAngle) * (radius + 20);
ctx.fillStyle = "black";
ctx.font = "14px sans-serif";
ctx.textAlign = "center";
ctx.fillText(labels[i], textX, textY);
startAngle = endAngle;
}
// 標題
ctx.font = "16px bold sans-serif";
ctx.textAlign = "center";
ctx.fillText("水果銷售比例", centerX, centerY - radius - 30);
---
arc() 畫出每個扇形。你可以加入滑鼠事件(例如 hover 放大或顯示百分比),或用 requestAnimationFrame() 加上動畫效果。是否要我幫你加上滑鼠 hover 顯示資料百分比的版本?
SVG(Scalable Vector Graphics)是一種基於 XML 的向量圖形格式,可在網頁中繪製線條、圖形、文字,並支援縮放與動畫。與點陣圖不同,SVG 在放大縮小時不會失真,適合圖表、ICON、地圖與流程圖等應用。
<svg width="200" height="100">
<rect x="10" y="10" width="50" height="50" fill="blue" />
<circle cx="100" cy="35" r="25" fill="green" />
<line x1="150" y1="10" x2="190" y2="60" stroke="red" stroke-width="2" />
<text x="10" y="90" font-size="14" fill="black">這是SVG</text>
</svg>
<rect>:矩形<circle>:圓形<ellipse>:橢圓<line>:線段<polyline>、<polygon>:折線與多邊形<path>:自由繪圖路徑(可畫曲線、複雜形狀)<text>:文字
<svg width="100" height="100">
<circle cx="50" cy="50" r="40" fill="orange" onclick="alert('你點到了圓形')" />
</svg>
可透過 CSS 或 <animate> 標籤製作動畫:
<circle cx="30" cy="50" r="20" fill="blue">
<animate attributeName="cx" from="30" to="170" dur="2s" repeatCount="indefinite" />
</circle>
<svg id="mysvg" width="200" height="100">
<circle id="c1" cx="50" cy="50" r="30" fill="gray" />
</svg>
<script>
document.getElementById("c1").setAttribute("fill", "red");
</script>
SVG 是網頁前端中非常重要的圖形標準之一,具有高解析度、互動性與動畫性,並可與 HTML/CSS/JavaScript 無縫整合。適合需要精確、縮放性強的圖形表現場景。
在 SVG 中可透過 <symbol> 或 <defs> 定義一次圖案,再用 <use> 在其他地方重複引用,節省代碼並提高一致性。
<svg width="0" height="0" style="position:absolute">
<symbol id="star" viewBox="0 0 100 100">
<polygon points="50,5 61,39 98,39 68,59 79,91 50,70 21,91 32,59 2,39 39,39"
fill="gold" stroke="black" stroke-width="2"/>
</symbol>
</svg>
<svg width="200" height="100">
<use href="#star" x="0" y="0" width="50" height="50"/>
<use href="#star" x="60" y="0" width="50" height="50" fill="red"/>
<use href="#star" x="120" y="0" width="50" height="50" fill="blue"/>
</svg>
<symbol>:定義圖案內容,可重複使用<use>:插入圖案,可指定位置與大小href:指向 symbol 的 id(舊寫法為 xlink:href)<use> 可改變 fill、stroke 等屬性,覆蓋原始定義。
<use href="#id"> 為現代寫法(舊版瀏覽器使用 xlink:href)<symbol> 放在 DOM 頂部或絕對隱藏透過 <symbol> + <use>,SVG 可實現元件化、模組化圖形開發,既可重複使用也方便管理樣式與位置,非常適合圖示設計與資料視覺化應用。
WebGL(Web Graphics Library)是一套基於 OpenGL ES 的 JavaScript API,可在瀏覽器中使用 HTML5 的 <canvas> 元素進行 2D 和 3D 圖形的硬體加速繪製,不需要任何外掛。
繪製一個有顏色的三角形:
<canvas id="glCanvas" width="300" height="300"></canvas>
<script>
const canvas = document.getElementById('glCanvas');
const gl = canvas.getContext('webgl');
if (!gl) {
alert("你的瀏覽器不支援 WebGL");
}
const vertexShaderSource = `
attribute vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0, 1);
}
`;
const fragmentShaderSource = `
void main() {
gl_FragColor = vec4(1, 0, 0, 1); // 紅色
}
`;
function createShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
return shader;
}
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
0, 1,
-1, -1,
1, -1
]), gl.STATIC_DRAW);
const posAttribLoc = gl.getAttribLocation(program, "a_position");
gl.enableVertexAttribArray(posAttribLoc);
gl.vertexAttribPointer(posAttribLoc, 2, gl.FLOAT, false, 0, 0);
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>
WebGL 為網頁開發者提供 GPU 加速的 3D 圖形繪製能力,是現代 Web 遊戲、數位藝術、模擬與視覺化的核心技術之一。雖然原生 WebGL 較為底層,但可搭配高階函式庫簡化開發流程。
Spirograph 是一種用於創建複雜圖形的幾何圖案,其原理是利用兩個圓形的轉動來描繪出多重圓形和波浪形的曲線。這種圖形通常用於藝術創作和教育,能夠展現數學中的幾何美感。
以下是使用 HTML5 的 <canvas> 元素和 JavaScript 實現 Spirograph 的範例:
| 程式庫名稱 | 語法表達性 | 圖形類型 | 適合對象 | 是否支援互動 | 是否支援動畫 |
|---|---|---|---|---|---|
| Mermaid.js | 極高(使用類 Markdown 語法) | 流程圖、序列圖、甘特圖、ER圖、Class圖 | 文件視覺化、快速原型 | 有限支援 | 部分支援 |
| D3.js | 中等(需要理解資料綁定與 DOM 操作) | 幾乎所有圖形(自訂性極高) | 進階資料視覺化開發者 | 完整支援 | 完整支援 |
| Cytoscape.js | 高(以 JSON 定義節點與邊) | 網路圖、流程圖 | 生物資訊、社交網絡分析 | 完整支援 | 部分支援 |
| Vega / Vega-Lite | 高(使用 JSON 宣告式描述圖表) | 統計圖表(條狀圖、散佈圖等) | 資料科學、儀表板設計 | 支援 | 部分支援 |
| Graphviz via Viz.js | 高(DOT 語法類似文字編程) | 流程圖、圖論結構 | 學術用途、快速架構圖 | 不支援 | 不支援 |
| JSXGraph | 高(幾何語意清晰) | 幾何圖形、座標圖 | 數學教育 | 支援 | 支援 |
Chart.js 是一個開源、輕量級且功能強大的 JavaScript 圖表繪製函式庫,
可在 HTML5 的 <canvas> 元素上繪製各種互動式圖表。
它以簡潔的 API、漂亮的預設樣式與高度可客製化的選項著稱,
適合快速將資料可視化於網站或應用程式中。
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
npm install chart.js
<canvas id="myChart"></canvas>
<script>
const ctx = document.getElementById('myChart').getContext('2d');
new Chart(ctx, {
type: 'bar',
data: {
labels: ['紅色', '藍色', '黃色', '綠色', '紫色', '橘色'],
datasets: [{
label: '票數',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: [
'rgba(255, 99, 132, 0.6)',
'rgba(54, 162, 235, 0.6)',
'rgba(255, 206, 86, 0.6)',
'rgba(75, 192, 192, 0.6)',
'rgba(153, 102, 255, 0.6)',
'rgba(255, 159, 64, 0.6)'
],
borderWidth: 1
}]
},
options: {
responsive: true,
scales: {
y: { beginAtZero: true }
}
}
});
</script>
---
| 圖表類型 | 設定 type | 用途說明 |
|---|---|---|
| 折線圖 | line | 顯示時間序列或趨勢資料。 |
| 長條圖 | bar | 比較不同分類的數值。 |
| 圓餅圖 | pie | 顯示整體比例分配。 |
| 甜甜圈圖 | doughnut | 圓餅圖的變體,中央可留白顯示標題。 |
| 雷達圖 | radar | 多維度資料的比較。 |
| 極區圖 | polarArea | 結合圓餅與長條的效果。 |
可以使用下列方式檢查 Chart.js 的版本:
console.log(Chart.version);
---
以下範例示範如何從 HTML <table> 讀取資料,並使用 JavaScript 動態繪製圓餅圖。此範例使用 Chart.js,簡單易用且支援自動配色與動畫。
<!-- 表格資料 -->
<table id="dataTable" border="1" style="margin:10px auto;">
<tr><th>類別</th><th>數值</th></tr>
<tr><td>蘋果</td><td>30</td></tr>
<tr><td>香蕉</td><td>15</td></tr>
<tr><td>櫻桃</td><td>25</td></tr>
<tr><td>芒果</td><td>20</td></tr>
</table>
<!-- 圓餅圖容器 -->
<canvas id="pieChart" width="400" height="400"></canvas>
<!-- 載入 Chart.js -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
---
// 讀取表格資料
const table = document.getElementById("dataTable");
const labels = [];
const values = [];
for (let i = 1; i < table.rows.length; i++) { // 跳過表頭
const row = table.rows[i];
labels.push(row.cells[0].textContent);
values.push(parseFloat(row.cells[1].textContent));
}
// 建立 Chart.js 圓餅圖
const ctx = document.getElementById("pieChart").getContext("2d");
new Chart(ctx, {
type: "pie",
data: {
labels: labels,
datasets: [{
data: values,
backgroundColor: [
"rgba(255, 99, 132, 0.7)",
"rgba(54, 162, 235, 0.7)",
"rgba(255, 206, 86, 0.7)",
"rgba(75, 192, 192, 0.7)"
],
borderColor: "white",
borderWidth: 2
}]
},
options: {
responsive: true,
plugins: {
legend: { position: "bottom" },
title: { display: true, text: "水果銷售比例" }
}
}
});
---
table 中動態擷取資料,不需手動定義。type: "pie" 為 "doughnut" 可切換為甜甜圈圖。若想在純 JavaScript(不使用外部 library)中繪製,可使用 CanvasRenderingContext2D.arc() 自行繪製扇形。要我幫你示範「不使用 Chart.js」的版本嗎?
在 HTML 中,您可以使用 <svg> 標籤來繪製基本的 UML 類別圖。以下是一個範例,展示如何使用矩形和文字來代表一個簡單的類別。
<svg width="300" height="200">
<rect x="50" y="20" width="200" height="30" fill="lightblue" stroke="black"/>
<text x="60" y="40" font-family="Arial" font-size="16">Class Name</text>
<rect x="50" y="50" width="200" height="50" fill="white" stroke="black"/>
<text x="60" y="70" font-family="Arial" font-size="14">+ attribute1 : Type</text>
<text x="60" y="90" font-family="Arial" font-size="14">+ attribute2 : Type</text>
<rect x="50" y="100" width="200" height="50" fill="white" stroke="black"/>
<text x="60" y="120" font-family="Arial" font-size="14">+ method1() : ReturnType</text>
<text x="60" y="140" font-family="Arial" font-size="14">+ method2() : ReturnType</text>
</svg>
可以利用 HTML 和 CSS 的樣式來定義不同的 UML 元件。下面的範例展示如何使用 <div> 和 CSS 來繪製一個類別框,並調整其樣式來模仿 UML
類別圖的結構。
<style>
.class-box {
width: 200px;
border: 1px solid black;
margin: 10px;
}
.header {
background-color: lightblue;
text-align: center;
font-weight: bold;
}
.attributes, .methods {
padding: 10px;
border-top: 1px solid black;
}
</style>
<div class="class-box">
<div class="header">ClassName</div>
<div class="attributes">
+ attribute1 : Type <br>
+ attribute2 : Type
</div>
<div class="methods">
+ method1() : ReturnType <br>
+ method2() : ReturnType
</div>
</div>
為了在 HTML 中繪製更複雜的 UML 圖,可以使用 mermaid.js 這樣的外部 JavaScript 庫。它支援多種 UML 圖表,並且可以直接嵌入 HTML。首先需要引用 mermaid.js,然後使用
<pre> 標籤撰寫 UML 圖表定義。
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
mermaid.initialize({ startOnLoad: true });
</script>
<pre class="mermaid">
classDiagram
Class01 <|-- Class02 : Inheritance
Class01 : +method1() void
Class02 : +method2() void
Class03 : +attribute int
Class04 : +method() void
</pre>
classDiagram
Class01 <|-- Class02 : Inheritance
Class01 : +method1() void
Class02 : +method2() void
Class03 : +attribute int
Class04 : +method() void
這樣的範例可以輕鬆地使用 mermaid.js 繪製出更複雜且清晰的 UML 圖,並且支援不同的圖表類型。
此範例展示類別之間的繼承、組合、聚合和關聯。
<pre class="mermaid">
classDiagram
Animal <|-- Mammal
Animal <|-- Bird
Mammal o-- Dog : has-a
Bird --> Wing : has-a
class Animal {
+String name
+int age
+eat() void
}
class Mammal {
+hasFur() bool
}
class Dog {
+bark() void
}
class Bird {
+fly() void
}
class Wing {
+wingSpan int
}
</pre>
classDiagram
Animal <|-- Mammal
Animal <|-- Bird
Mammal o-- Dog : has-a
Bird --> Wing : has-a
class Animal {
+String name
+int age
+eat() void
}
class Mammal {
+hasFur() bool
}
class Dog {
+bark() void
}
class Bird {
+fly() void
}
class Wing {
+wingSpan int
}
說明:此範例展示了多種關係:
Animal 是 Mammal 和 Bird 的超類別。Mammal 與 Dog 的組合關係由 o-- 表示。Bird 與 Wing 的聚合關係由 --> 表示。此範例展示如何在類別之間表示多重性(1..*、0..1 等)和角色。
<pre class="mermaid">
classDiagram
Customer "1" --> "0..*" Order : places
Order "1" --> "1" Payment : includes
class Customer {
+String name
+String email
+placeOrder() void
}
class Order {
+int orderId
+String date
+calculateTotal() float
}
class Payment {
+float amount
+String method
+processPayment() void
}
</pre>
classDiagram
Customer "1" --> "0..*" Order : places
Order "1" --> "1" Payment : includes
class Customer {
+String name
+String email
+placeOrder() void
}
class Order {
+int orderId
+String date
+calculateTotal() float
}
class Payment {
+float amount
+String method
+processPayment() void
}
說明:
Customer 可以擁有多個 Order,每個 Order 都對應一個
Payment。places 和 includes)。此範例展示如何在 Mermaid.js 中定義介面和抽象類別。
<pre class="mermaid">
classDiagram
class Shape {
<<_abstract_>>
+area() float
+perimeter() float
}
Shape <|-- Rectangle
Shape <|-- Circle
class Rectangle {
+width float
+height float
+area() float
+perimeter() float
}
class Circle {
+radius float
+area() float
+perimeter() float
}
</pre>
classDiagram
class Shape {
<<_abstract_>>
+area() float
+perimeter() float
}
Shape <|-- Rectangle
Shape <|-- Circle
class Rectangle {
+width : float
+height : float
+area() float
+perimeter() float
}
class Circle {
+radius : float
+area() float
+perimeter() float
}
說明:
Shape 是抽象類別,以 <<abstract>> 標記。Rectangle 和 Circle 繼承了 Shape 並實現其方法。此範例展示類別繼承和介面實作的混合用法。
<pre class="mermaid">
classDiagram
class Flyable {
<<_interface_>>
+fly() void
}
class Bird {
+String species
+String color
+sing() void
}
class Airplane {
+String model
+int capacity
+takeOff() void
}
Bird ..|> Flyable : implements
Airplane ..|> Flyable : implements
</pre>
classDiagram
class Flyable {
<<_interface_>>
+fly() void
}
class Bird {
+String species
+String color
+sing() void
}
class Airplane {
+String model
+int capacity
+takeOff() void
}
Bird ..|> Flyable : implements
Airplane ..|> Flyable : implements
說明:
Flyable 為介面,並定義 fly() 方法。Bird 和 Airplane 都實作了 Flyable 介面,使用
..|> 符號表示。
flowchart TD
A[開始] --> B{是否需要繼續?}
B -- 是 --> C[執行操作]
B -- 否 --> D[結束]
C --> D
Mermaid 提供官方的 Mermaid Live Editor,可以即時測試並檢查語法錯誤。將 Mermaid 語法貼上後,如果有錯誤,編輯器會顯示具體錯誤訊息,讓你更快地排除問題。
如果你的 Mermaid 圖表過於複雜,建議分段測試。例如,先移除一些類別或關係,只留下最基本的結構,逐步增加元素,這樣可以更快找出可能的語法錯誤來源。
Mermaid.js 的不同版本可能對語法有不同的支持。確保你使用的是最新版,或者在測試環境中確認你的 Mermaid.js 版本是否支持使用的語法功能。
+attribute : type 來標示屬性。<|-- 或 -->)是否正確,這些符號用於表示類別關係。<<abstract>> 或其它特殊標記,建議逐一移除或修改來確認是否造成錯誤。在瀏覽器的開發者工具中查看 JavaScript console,如果 Mermaid 圖表未正確生成,console 中可能會顯示具體錯誤訊息或提示,幫助你找出語法錯誤。
Mermaid 官方文件提供詳細的語法指南,可以幫助你確認語法使用是否正確。官方文件位於 Mermaid.js 官方網站。
以下是一個簡單的流程圖範例,說明決策與行動之間的邏輯關係。
flowchart TD
A[開始] --> B{是否需要繼續?}
B -- 是 --> C[執行操作]
B -- 否 --> D[結束]
C --> D
將上述流程圖語法粘貼到支持 Mermaid 的工具(如 Markdown 編輯器或 Mermaid 在線工具)中,即可生成出圖形。
此 JavaScript 函式庫可為 Mermaid.js 圖表加入可縮放的滑桿功能,使用者可透過 <input type="range"> 控制圖表的縮放比例。函式庫使用 transform: scale() 實現視覺縮放,無需重新渲染 Mermaid。
// mermaidZoomSlider.js
export function setupMermaidZoomSlider({
sliderId = "zoomSlider",
diagramContainerId = "mermaidContainer",
min = 0.1,
max = 3,
step = 0.1,
initial = 1
} = {}) {
window.addEventListener("load", () => {
const slider = document.getElementById(sliderId);
const container = document.getElementById(diagramContainerId);
if (!slider || !container) {
console.warn("Mermaid zoom slider: Missing slider or container element");
return;
}
// 初始化 slider 屬性
slider.min = min;
slider.max = max;
slider.step = step;
slider.value = initial;
// 設定初始縮放
container.style.transformOrigin = "top left";
container.style.transform = `scale(${initial})`;
// 事件監聽:縮放
slider.addEventListener("input", () => {
const scale = parseFloat(slider.value);
container.style.transform = `scale(${scale})`;
});
});
}
<!-- HTML -->
<div>
<input type="range" id="zoomSlider">
</div>
<div id="mermaidContainer">
<pre class="mermaid">
graph TD;
A-->B;
B-->C;
</pre>
</div>
<!-- JavaScript 模組引入 -->
<script type="module">
import mermaid from "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
import { setupMermaidZoomSlider } from "./mermaidZoomSlider.js";
mermaid.initialize({ startOnLoad: true });
setupMermaidZoomSlider({
sliderId: "zoomSlider",
diagramContainerId: "mermaidContainer",
min: 0.2,
max: 3,
step: 0.1,
initial: 1
});
</script>
若需要拖曳移動、縮放重設等進階功能,可進一步擴充此函式庫,例如整合滑鼠拖拉與縮放重設按鈕。
在 Mermaid.js 的圖中使用 -->、===> 等標記來建立節點之間的連線,不同的符號代表不同的線條樣式。
| 語法 | 樣式 | 說明 |
|---|---|---|
--> |
──> | 一般實線箭頭 |
---> |
───> | 與 --> 相同(語法容錯) |
-- text --> |
── text ──> | 帶文字標籤的實線箭頭 |
-.-> |
-.-> | 虛線箭頭 |
-. text .-> |
-. text .-> | 帶文字的虛線箭頭 |
==> |
===> | 粗實線箭頭 |
== text ==> |
== text ==> | 帶文字的粗線箭頭 |
--o |
──○ | 圓頭無方向線(class diagram 常用) |
--|> |
──▷ | 實心箭頭(class diagram 常用) |
--> | label | |
──>(帶雙側文字) | Mermaid 支援樣式註解標籤 |
graph TD
A[開始] --> B[步驟一]
B -.-> C[非同步處理]
C ==> D[強烈依賴]
D -- text --> E[帶文字的連線]
E --o F[圓頭]
F --|> G[實心箭頭]
graph)、類別圖(classDiagram)、狀態圖等樣式略有差異Mermaid.js 提供多種線條語法樣式,讓使用者能清晰表達流程、邏輯與關聯,透過實線、虛線、粗線與圖示端點等搭配,可建立簡潔又結構分明的圖表。
D3.js (Data-Driven Documents) 是一個基於 JavaScript 的開源程式庫,用於將數據轉換為動態且互動的可視化效果。它使用網頁標準技術如 SVG、HTML 和 CSS,提供強大的工具來處理數據和繪製圖形。
d3.select() 和 d3.selectAll()。
D3.js 被廣泛應用於各種數據可視化場景,例如:
要學習 D3.js,可以參考以下資源:
D3.js 是一個功能強大且靈活的數據可視化工具,適合需要高度自訂化圖表和互動效果的開發者。雖然學習曲線稍高,但一旦掌握,其應用潛力無窮。
本範例使用 D3.js 繪製一個簡單的樹狀圖,展示如何將階層結構資料視覺化。以下是主要步驟:
tree() 函數生成樹狀佈局。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>D3.js Tree Diagram Example</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
.node circle {
fill: steelblue;
}
.node text {
font: 12px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
</style>
</head>
<body>
<script>
const width = 800;
const height = 600;
const treeData = {
name: "CEO",
children: [
{
name: "CTO",
children: [
{ name: "Engineering Manager" },
{ name: "Product Manager" }
]
},
{
name: "CFO",
children: [
{ name: "Accountant" },
{ name: "Finance Analyst" }
]
}
]
};
const svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(40,40)");
const treeLayout = d3.tree().size([height - 100, width - 160]);
const root = d3.hierarchy(treeData);
treeLayout(root);
svg.selectAll(".link")
.data(root.links())
.enter()
.append("path")
.attr("class", "link")
.attr("d", d3.linkHorizontal()
.x(d => d.y)
.y(d => d.x)
);
const nodes = svg.selectAll(".node")
.data(root.descendants())
.enter()
.append("g")
.attr("class", "node")
.attr("transform", d => `translate(${d.y},${d.x})`);
nodes.append("circle").attr("r", 5);
nodes.append("text")
.attr("dy", 3)
.attr("x", d => d.children ? -10 : 10)
.style("text-anchor", d => d.children ? "end" : "start")
.text(d => d.data.name);
</script>
</body>
</html>
運行此程式碼後,您將看到一個樹狀圖:
CEO)。CTO 和 CFO)向右展開。此範例可以擴展至更複雜的階層結構,或調整樣式以適應不同需求。例如:
矩形樹狀圖是一種用巢狀矩形方式來顯示階層資料的視覺化技術。每個矩形的面積代表一個數值大小,例如銷售額或檔案容量,而每個矩形也可以進一步巢狀,用來表示子分類。
Cytoscape.js 是用來繪製網路圖(Graph)的 JavaScript 函式庫,使用 JSON 定義節點與邊,語法簡潔,支援互動與樣式客製化。
elements:定義節點(node)與邊(edge)資料style:控制樣式,如顏色、箭頭、標籤layout:圖形排列方式(可選 grid、circle、cose 等)classes 定義節點群組並指定不同樣式| 程式庫名稱 | 適用性 | 特點 | 是否支援互動 | 說明 |
|---|---|---|---|---|
| JointJS | ★★★★★ | 繪圖自由度高、可擴充電路元件符號 | ✔️ | 可繪製邏輯電路、流程圖,免費版功能已足夠 |
| GoJS | ★★★★☆ | 強大的圖形與資料模型支援 | ✔️ | 非自由軟體,但有免費試用;常用於產線圖與電路圖 |
| SVG.js | ★★★☆☆ | 輕量、支援精準繪圖 | ✔️ | 需自行設計元件(電阻、電容等),適合細部控制 |
| Konva.js | ★★★☆☆ | Canvas 與 SVG 都支援 | ✔️ | 適合需要拖曳、點擊等互動行為的設計工具 |
| ELK.js | ★★☆☆☆ | 自動佈局優秀 | ✖️ | 只負責佈局演算法(可與 JointJS 搭配) |
本工具可將以 x 和 y 為自變數的 z = f(x, y) 方程式繪製成 3D 曲面圖,並提供滑鼠操作旋轉、縮放、平移的互動功能。
<div id="plot3d" style="width:100%; height:600px;"></div>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<script type="module">
// 定義 z = f(x, y) 的函數(可更換為任意方程式)
function computeZ(x, y) {
return Math.sin(x) * Math.cos(y); // z = sin(x) * cos(y)
}
const xRange = numeric.linspace(-5, 5, 50);
const yRange = numeric.linspace(-5, 5, 50);
// 建立 z 資料
const zValues = xRange.map(x =>
yRange.map(y => computeZ(x, y))
);
const data = [{
type: 'surface',
x: xRange,
y: yRange,
z: zValues,
colorscale: 'Viridis'
}];
const layout = {
title: 'z = sin(x) * cos(y)',
autosize: true,
scene: {
xaxis: { title: 'X 軸' },
yaxis: { title: 'Y 軸' },
zaxis: { title: 'Z 軸' }
}
};
Plotly.newPlot('plot3d', data, layout);
</script>
<!-- numeric.js 用來產生 linspace 數列 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/numeric/1.2.6/numeric.min.js"></script>
z = Math.sin(x * y) → 波紋狀z = x * x - y * y → 鞍形曲面z = Math.exp(-(x * x + y * y)) → 高斯峰此範例使用 Plotly.js 提供互動式 3D 視覺化,並搭配 numeric.js 輔助產生數值網格。你可以自由變更 computeZ 函數中的內容來畫出任意的三維曲面。
3Dmol.js 是一個開源且專為瀏覽器設計的 WebGL 化學分子可視化函式庫,可直接在網頁中繪製分子結構。
<div id="viewer" style="width:400px;height:400px;"></div>
<script src="https://3dmol.org/build/3Dmol-min.js"></script>
<script>
const viewer = $3Dmol.createViewer("viewer", { backgroundColor: "white" });
viewer.addModel("C1=CC=CC=C1", "smi"); // 苯的 SMILES 結構
viewer.setStyle({}, {stick: {}, sphere: {scale: 0.3}});
viewer.zoomTo();
viewer.render();
</script>
ChemDoodle 提供 2D 與 3D 結構繪圖,支援多種化學格式,適用於教學與網頁應用。
JSmol 是 Jmol 的 JavaScript 版本,適合顯示大分子如蛋白質或晶體結構。
Mol*(MolStar)是由 RCSB PDB 開發的高階結構視覺化工具,專為生物大分子設計。
| 函式庫 | 主要用途 | 是否開源 | 是否需授權 |
|---|---|---|---|
| 3Dmol.js | 通用3D分子視覺化 | ✅ | ❌ |
| ChemDoodle | 2D與3D教學、展示 | 部分 | ✅ |
| JSmol | 學術研究與教學 | ✅ | ❌ |
| Mol* | 蛋白質與生物分子視覺化 | ✅ | ❌ |
此範例使用 3Dmol.js 並採用 XYZ 格式 定義苯分子的原子座標,以正確顯示 3D 分子結構。
如果使用 SMILES 格式("smi")會出現錯誤 Unknown format: smi,因為該格式在部分 3Dmol.js 版本中未被支援。
benzene.html。python -m http.server)開啟。http://localhost:8000 檢視結果。<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>3Dmol.js 渲染苯分子</title>
<script src="https://3dmol.org/build/3Dmol-min.js"></script>
<style>
#viewer {
width: 600px;
height: 600px;
position: relative;
border: 1px solid #aaa;
}
</style>
</head>
<body>
<h2>3Dmol.js 苯分子展示 (XYZ 格式)</h2>
<div id="viewer"></div>
<script>
document.addEventListener("DOMContentLoaded", function () {
const viewer = $3Dmol.createViewer("viewer", { backgroundColor: "white" });
const xyzData = `
12
benzene
C 0.0000 1.3968 0.0000
H 0.0000 2.4903 0.0000
C -1.2096 0.6984 0.0000
H -2.1471 1.2451 0.0000
C -1.2096 -0.6984 0.0000
H -2.1471 -1.2451 0.0000
C 0.0000 -1.3968 0.0000
H 0.0000 -2.4903 0.0000
C 1.2096 -0.6984 0.0000
H 2.1471 -1.2451 0.0000
C 1.2096 0.6984 0.0000
H 2.1471 1.2451 0.0000
`;
viewer.addModel(xyzData, "xyz");
viewer.setStyle({}, {stick: {}, sphere: {scale: 0.3}});
viewer.zoomTo();
viewer.render();
});
</script>
</body>
</html>
file:// 開啟 HTML,建議使用本地 HTTP 伺服器。Google Maps JavaScript API 可讓開發者在網頁中嵌入互動式地圖, 並透過 JavaScript 動態新增標記(Marker)、圖層、文字標籤等自訂元素。 以下範例示範如何顯示地圖並加入自訂的標記。
---
前往 Google Cloud Console,啟用 Maps JavaScript API,
並建立一組 API 金鑰(API Key)。
取得後,在載入 script 時附加 ?key=YOUR_API_KEY。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Google Map with Custom Tags</title>
<style>
#map {
width: 100%;
height: 500px;
}
</style>
</head>
<body>
<h3>我的地圖</h3>
<div id="map"></div>
<!-- 載入 Google Maps JS API -->
<script async
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
</script>
<script>
function initMap() {
// 初始化地圖
const center = { lat: 25.033964, lng: 121.564468 }; // 台北101
const map = new google.maps.Map(document.getElementById("map"), {
zoom: 14,
center: center
});
// 建立自訂標記
const myTags = [
{ position: { lat: 25.034, lng: 121.565 }, title: "標記 A", content: "這是 A 點" },
{ position: { lat: 25.036, lng: 121.562 }, title: "標記 B", content: "這是 B 點" },
{ position: { lat: 25.032, lng: 121.568 }, title: "標記 C", content: "這是 C 點" }
];
// 建立資訊視窗(InfoWindow)
const infoWindow = new google.maps.InfoWindow();
// 將標記加到地圖上
myTags.forEach(tag => {
const marker = new google.maps.Marker({
position: tag.position,
map: map,
title: tag.title,
icon: {
url: "https://maps.google.com/mapfiles/ms/icons/blue-dot.png"
}
});
// 點擊顯示資訊
marker.addListener("click", () => {
infoWindow.setContent("<b>" + tag.title + "</b><br>" + tag.content);
infoWindow.open(map, marker);
});
});
}
</script>
</body>
</html>
---
icon 為自己的圖片(PNG、SVG)。google.maps.Polyline 或 Polygon 繪製線條與區域。map.setMapTypeId('satellite') 切換為衛星模式。| 屬性 | 用途 |
|---|---|
center | 設定地圖初始中心座標。 |
zoom | 地圖縮放等級(1–20)。 |
mapTypeId | 顯示樣式,可為 roadmap、satellite、hybrid、terrain。 |
icon | 自訂標記圖示。 |
infoWindow | 顯示點擊標記後的資訊視窗。 |
要在瀏覽器中播放指定的 MIDI 音色(例如吉他),可使用 Web MIDI API 或更簡單的是使用 Web Audio API 搭配 SoundFont 播放器,如 SoundFont Player 套件 soundfont-player。
<script src="https://unpkg.com/[email protected]/dist/soundfont-player.js"></script>
<button onclick="playDoReMi()">播放 Do Re Mi</button>
<script>
async function playDoReMi() {
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
const player = await Soundfont.instrument(audioCtx, 'acoustic_guitar_nylon');
const now = audioCtx.currentTime;
player.play('C4', now); // Do
player.play('D4', now + 0.5); // Re
player.play('E4', now + 1); // Mi
}
</script>
C4, D4, E4:代表 Do Re Miacoustic_guitar_nylon:SoundFont 的吉他音色(也可改為 electric_guitar_jazz 等)acoustic_guitar_nylonacoustic_guitar_steelelectric_guitar_jazzelectric_guitar_cleanelectric_guitar_mutedoverdriven_guitardistortion_guitarguitar_harmonics使用 soundfont-player 搭配 Web Audio API 能輕鬆實現 MIDI 級別的樂器播放功能,不需要安裝任何插件。只要指定音色與音高,即可快速實作如「do re mi」的音階旋律。
如果無法透過外部 SoundFont 播放音色,我們可以直接使用 Web Audio API 的 OscillatorNode 合成器播放 Do Re Mi,並模擬吉他風格(例如:短促聲音 + 弱音)
<button onclick="playDoReMi()">播放 Do Re Mi</button>
<script>
function playTone(frequency, startTime, duration, context) {
const osc = context.createOscillator();
const gain = context.createGain();
osc.type = "triangle"; // 接近吉他聲的合成波形,可改為 "square"、"sawtooth"
osc.frequency.value = frequency;
gain.gain.setValueAtTime(0.2, startTime);
gain.gain.exponentialRampToValueAtTime(0.001, startTime + duration);
osc.connect(gain);
gain.connect(context.destination);
osc.start(startTime);
osc.stop(startTime + duration);
}
function playDoReMi() {
const context = new (window.AudioContext || window.webkitAudioContext)();
const now = context.currentTime;
// Do Re Mi 的頻率 (C4, D4, E4)
playTone(261.63, now, 0.4, context); // C4
playTone(293.66, now + 0.5, 0.4, context); // D4
playTone(329.63, now + 1.0, 0.4, context); // E4
}
</script>
osc.type 或加上濾波器來模擬吉他音色triangle 或 sawtooth 波形gain.exponentialRampToValueAtTime())模擬撥弦使用純 Web Audio API 是最穩定與相容性最高的方式。若有進階需求,可再加上濾波器、回音、或整合 MIDI 音源。
| osc.type | 中文名稱 | 音色特性 | 常見模擬樂器 |
|---|---|---|---|
"sine" |
正弦波 | 最純淨、無諧波 | 純音、音叉、笛子、電子合成音 |
"square" |
方波 | 奇數諧波豐富,音色尖銳 | 合成器、8-bit 音效、電子鍵盤 |
"sawtooth" |
鋸齒波 | 包含所有諧波,音色厚實明亮 | 弦樂、吉他、銅管模擬 |
"triangle" |
三角波 | 只有奇數諧波,聲音較柔和 | 木管、柔和電吉他聲 |
"custom" |
自定波形 | 可自製任意波形 | 特殊合成音、真實模擬音色 |
const osc = audioContext.createOscillator();
osc.type = "sawtooth"; // 可改為 "sine", "square", "triangle", "custom"
osc.frequency.value = 440; // A4
osc.start();
const real = new Float32Array([0, 1, 0.5, 0.25]);
const imag = new Float32Array(real.length);
const wave = audioContext.createPeriodicWave(real, imag);
osc.setPeriodicWave(wave);
osc.type = "custom";
不同 osc.type 可模擬不同風格的樂器音色。若想模擬吉他建議從 sawtooth 或 triangle 開始,並搭配 Envelope(音量包絡)、濾波器與回音來細緻調整音質。
建議使用WebAudioFont這個開源 JavaScript 庫,它支援超過數千種 MIDI 音色,並包含吉他等樂器音色,音質較佳又易於整合。
'acoustic_guitar_steel''acoustic_guitar_nylon''electric_guitar_clean' ⋯⋯透過 WebAudioFont 結合 Web Audio API,你可以方便地使用真實 MIDI 音色(例如吉他)播放音符,解決純 Oscillator 合成音色單一的問題,同時避免之前 SoundFont 玩家無聲的狀況。
email: [email protected]