前言#
在远程办公和在线协作日益普及的今天,白板工具成为了团队沟通的重要载体。Excalidraw 以其独特的手绘风格和极简设计,在众多白板工具中脱颖而出。它不仅是一款优秀的绘图工具,更是一个开源项目的技术典范。
什么是 Excalidraw?#
Excalidraw 是一款开源的虚拟白板工具,专注于创建具有手绘风格的图表、草图和示意图。它的核心特点包括:
| 特性 | 描述 |
|---|---|
| 手绘风格 | 独特的"抖动"效果,让图形看起来像手绘的 |
| 极简界面 | 无干扰的绘图体验,学习成本几乎为零 |
| 实时协作 | 支持多人同时编辑,适合远程团队 |
| 离线支持 | PWA 应用,可离线使用 |
| 开源免费 | MIT 协议,可自由使用和二次开发 |
核心功能介绍#
1. 绘图工具#
Excalidraw 提供了丰富的绘图工具,覆盖大部分绘图需求:
- 矩形、菱形、椭圆:基础形状,支持圆角调整
- 箭头与线条:支持曲线、直线,可添加箭头
- 文本工具:支持富文本,可调整字体大小
- 自由绘制:手绘模式,自由创作
- 图片导入:支持拖拽导入图片
2. 手绘风格算法#
Excalidraw 最具特色的是其手绘风格算法。核心思路是为线条添加"抖动"效果:
// 简化的手绘效果实现
function generateRoughLine(points, options) {
const { roughness, bowing } = options;
return points.map((point, i) => {
// 添加随机偏移
const offsetX = (Math.random() - 0.5) * roughness;
const offsetY = (Math.random() - 0.5) * roughness;
// 添加弯曲效果
const bowOffset = Math.sin(i * 0.5) * bowing;
return {
x: point.x + offsetX + bowOffset,
y: point.y + offsetY
};
});
}实际上,Excalidraw 使用了 Rough.js 库来实现手绘效果,该库提供了丰富的手绘风格选项:
import rough from 'roughjs';
const rc = rough.canvas(canvasElement);
// 绘制手绘风格的矩形
rc.rectangle(10, 10, 100, 50, {
stroke: '#000000',
strokeWidth: 2,
roughness: 1.5, // 粗糙度
bowing: 1, // 弯曲度
fill: '#ffffff',
fillStyle: 'solid'
});3. 实时协作#
Excalidraw 支持多人实时协作,技术实现基于:
- WebSocket:实时同步绘制操作
- CRDT(Conflict-free Replicated Data Types):解决并发编辑冲突
- 广播机制:每个操作广播给所有协作者
// 简化的协作同步逻辑
class CollaborationManager {
constructor(socket) {
this.socket = socket;
this.localVersion = 0;
}
// 发送本地操作
broadcastAction(action) {
this.socket.emit('draw', {
action,
version: ++this.localVersion,
timestamp: Date.now()
});
}
// 接收远程操作
onRemoteAction(data) {
if (data.version > this.localVersion) {
this.applyAction(data.action);
this.localVersion = data.version;
}
}
}4. 无限画布#
Excalidraw 采用无限画布设计,支持:
- 缩放:鼠标滚轮或手势缩放
- 平移:拖拽移动画布
- 坐标系:基于场景坐标,不受画布尺寸限制
// 视口变换
class Viewport {
constructor() {
this.zoom = 1;
this.scrollX = 0;
this.scrollY = 0;
}
// 场景坐标转屏幕坐标
sceneToScreen(x, y) {
return {
x: (x - this.scrollX) * this.zoom,
y: (y - this.scrollY) * this.zoom
};
}
// 屏幕坐标转场景坐标
screenToScene(x, y) {
return {
x: x / this.zoom + this.scrollX,
y: y / this.zoom + this.scrollY
};
}
}技术架构#
技术栈#
| 技术 | 用途 |
|---|---|
| React | UI 框架 |
| TypeScript | 类型安全 |
| Rough.js | 手绘效果渲染 |
| Socket.io | 实时通信 |
| Yjs | CRDT 实现 |
| Vite | 构建工具 |
项目结构#
excalidraw/
├── src/
│ ├── components/ # React 组件
│ │ ├── App.tsx
│ │ ├── Canvas.tsx
│ │ └── ...
│ ├── element/ # 图形元素定义
│ │ ├── newElement.ts
│ │ ├── mutateElement.ts
│ │ └── ...
│ ├── scene/ # 场景管理
│ ├── renderer/ # 渲染逻辑
│ ├── data/ # 数据持久化
│ └── collab/ # 协作功能
├── public/
│ └── index.html
└── package.json核心数据结构#
Excalidraw 的核心是元素(Element)数据结构:
type ExcalidrawElement = {
id: string;
type: "rectangle" | "ellipse" | "diamond" | "arrow" | "line" | "text" | "freedraw";
x: number;
y: number;
width: number;
height: number;
angle: number;
strokeColor: string;
backgroundColor: string;
fillStyle: "solid" | "hachure" | "cross-hatch";
strokeWidth: number;
roughness: number;
opacity: number;
// ... 更多属性
};
type AppState = {
viewBackgroundColor: string;
currentItemStrokeColor: string;
zoom: { value: number };
scrollX: number;
scrollY: number;
// ... 更多状态
};实际应用场景#
1. 架构图绘制#
Excalidraw 非常适合绘制系统架构图:
┌─────────────┐ ┌─────────────┐
│ Client │─────▶│ Server │
└─────────────┘ └──────┬──────┘
│
▼
┌─────────────┐
│ Database │
└─────────────┘2. 流程图与思维导图#
手绘风格让流程图更加生动,适合:
- 产品需求讨论
- 技术方案设计
- 会议记录
3. 快速原型#
设计师可以用 Excalidraw 快速绘制 UI 原型:
- 线框图
- 交互流程
- 页面布局
4. 教学与演示#
教育工作者可以用它:
- 绘制示意图
- 解释复杂概念
- 制作教学材料
集成与扩展#
嵌入到自己的项目#
Excalidraw 提供了 npm 包,可以嵌入到任何 React 项目中:
npm install @excalidraw/excalidrawimport { Excalidraw } from "@excalidraw/excalidraw";
import "@excalidraw/excalidraw/index.css";
function App() {
return (
<div style={{ height: "500px" }}>
<Excalidraw
initialData={{
elements: [],
appState: {}
}}
onChange={(elements, appState) => {
console.log("Elements:", elements);
}}
/>
</div>
);
}导出功能#
Excalidraw 支持多种导出格式:
import { exportToSvg, exportToBlob, exportToCanvas } from "@excalidraw/excalidraw";
// 导出为 SVG
const svg = await exportToSvg({
elements,
appState,
files
});
// 导出为 PNG Blob
const blob = await exportToBlob({
elements,
appState,
files,
mimeType: "image/png"
});
// 下载文件
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "diagram.png";
a.click();自定义工具#
可以通过 API 扩展自定义工具:
// 自定义元素类型
const customElement = {
type: "custom",
x: 100,
y: 100,
width: 200,
height: 100,
// 自定义渲染逻辑
customData: {
// 你的自定义数据
}
};与其他工具对比#
| 工具 | 风格 | 协作 | 开源 | 价格 |
|---|---|---|---|---|
| Excalidraw | 手绘 | 支持 | 是 | 免费 |
| Miro | 精致 | 支持 | 否 | 付费 |
| Draw.io | 标准 | 有限 | 是 | 免费 |
| Figma | 精致 | 支持 | 否 | 免费/付费 |
| Whimsical | 手绘 | 支持 | 否 | 付费 |
最佳实践#
1. 快捷键使用#
熟练使用快捷键可以大幅提升效率:
| 快捷键 | 功能 |
|---|---|
R | 矩形工具 |
O | 椭圆工具 |
D | 菱形工具 |
A | 箭头工具 |
T | 文本工具 |
H | 手绘工具 |
V | 选择工具 |
Space + 拖拽 | 平移画布 |
Ctrl/Cmd + 滚轮 | 缩放 |
2. 库(Library)的使用#
Excalidraw 支持自定义图形库,可以保存常用图形:
// 创建自定义库
const libraryItems = [
{
status: "published",
elements: [
// 你的自定义图形元素
]
}
];
// 导入库
await Library.loadLibrary(libraryItems);3. 文件格式#
Excalidraw 使用 JSON 格式存储数据:
{
"type": "excalidraw",
"version": 2,
"source": "https://excalidraw.com",
"elements": [
{
"type": "rectangle",
"version": 1,
"x": 100,
"y": 100,
"width": 200,
"height": 100
}
],
"appState": {
"viewBackgroundColor": "#ffffff"
}
}总结#
Excalidraw 以其独特的手绘风格和极简设计,成为了白板工具领域的一股清流。它的成功不仅在于产品本身,更在于开源社区的活跃和技术的开放性。
核心优势#
- 独特风格:手绘效果让图表更有温度
- 开箱即用:无需学习,上手即用
- 开源免费:MIT 协议,可自由使用
- 可扩展:提供 npm 包,易于集成
适用场景#
- 技术架构图绘制
- 产品原型设计
- 团队协作讨论
- 教学演示
参考资源#
如果你正在寻找一款简洁、优雅的白板工具,不妨试试 Excalidraw!
