一文詳解前端開源的canvas工具庫Fabric.js

Fabric.js 是一個功能強(qiáng)大的 HTML5 Canvas 庫,它通過面向?qū)ο蟮姆绞胶喕?Canvas 操作,為開發(fā)者提供了豐富的圖形操作功能和直觀的 API 接口。
一、核心特性
1. 基礎(chǔ)能力
- 完整的對象模型:將畫布元素抽象為對象(矩形、圓形、路徑等)
- 交互式操作:內(nèi)置支持拖拽、旋轉(zhuǎn)、縮放等交互
- 豐富的圖形類型:支持路徑、圖像、文本、組等
- 動畫系統(tǒng):提供流暢的動畫支持
- 濾鏡效果:內(nèi)置多種圖像濾鏡
- 序列化/反序列化:支持 JSON 導(dǎo)入導(dǎo)出
2. 高級功能
- 自由繪制:鉛筆、噴槍等繪畫工具
- SVG 支持:解析和渲染 SVG
- 事件系統(tǒng):完善的鼠標(biāo)/觸摸事件
- 裁剪和蒙版:支持復(fù)雜裁剪操作
- 自定義擴(kuò)展:可擴(kuò)展新的對象類型和功能
二、基本架構(gòu)
1. 核心類結(jié)構(gòu)

2. 對象繼承體系
fabric.Object:所有圖形基類fabric.Rect:矩形fabric.Circle:圓形fabric.Triangle:三角形fabric.Text:文本fabric.Image:圖像fabric.Path:路徑fabric.Group:對象組fabric.ActiveSelection:活動選擇組
三、核心 API 詳解
1. 畫布初始化
// 創(chuàng)建畫布實(shí)例
const canvas = new fabric.Canvas('canvas-id', {
width: 800, // 畫布寬度
height: 600, // 畫布高度
backgroundColor: '#f5f5f5', // 背景色
selection: true, // 是否啟用選擇
preserveObjectStacking: true // 保持對象堆疊順序
});
2. 基本圖形創(chuàng)建
// 創(chuàng)建矩形
const rect = new fabric.Rect({
left: 100,
top: 100,
width: 200,
height: 100,
fill: 'red',
angle: 45,
stroke: 'black',
strokeWidth: 2
});
// 創(chuàng)建圓形
const circle = new fabric.Circle({
radius: 50,
fill: 'blue',
left: 300,
top: 200
});
// 添加對象到畫布
canvas.add(rect, circle);
canvas.renderAll(); // 渲染更新
3. 交互功能
// 對象選擇事件
canvas.on('selection:created', (e) => {
console.log('選中對象:', e.selected);
});
// 對象移動事件
canvas.on('object:moving', (e) => {
console.log('移動對象:', e.target);
});
// 對象縮放事件
canvas.on('object:scaling', (e) => {
console.log('縮放對象:', e.target);
});
四、高級功能實(shí)現(xiàn)
1. 自由繪制實(shí)現(xiàn)
// 啟用自由繪制
canvas.isDrawingMode = true;
// 配置畫筆
canvas.freeDrawingBrush = new fabric.PencilBrush(canvas);
canvas.freeDrawingBrush.width = 5;
canvas.freeDrawingBrush.color = '#000000';
// 繪制完成事件
canvas.on('path:created', (e) => {
console.log('繪制路徑:', e.path);
});
2. 動畫系統(tǒng)
// 簡單動畫
rect.animate('angle', 360, {
duration: 1000,
onChange: canvas.renderAll.bind(canvas),
easing: fabric.util.ease.easeInOutQuad
});
// 復(fù)雜動畫
fabric.util.animate({
startValue: 0,
endValue: 100,
duration: 500,
onChange: (value) => {
circle.set('left', value);
canvas.renderAll();
},
onComplete: () => {
console.log('動畫完成');
}
});
3. 濾鏡應(yīng)用
// 創(chuàng)建圖像對象
fabric.Image.fromURL('image.jpg', (img) => {
// 添加濾鏡
img.filters.push(
new fabric.Image.filters.Grayscale(),
new fabric.Image.filters.Brightness({ brightness: 0.2 })
);
img.applyFilters();
canvas.add(img);
});
五、性能優(yōu)化技巧
1. 渲染優(yōu)化
// 批量操作時暫停渲染
canvas.renderOnAddRemove = false;
// 執(zhí)行多個操作...
canvas.renderOnAddRemove = true;
canvas.renderAll();
// 使用 requestAnimationFrame
function animate() {
requestAnimationFrame(() => {
// 更新對象屬性
canvas.renderAll();
animate();
});
}
2. 內(nèi)存管理
// 移除對象時徹底銷毀 canvas.remove(object); object = null; // 清理畫布 canvas.dispose();
3. 大數(shù)據(jù)量優(yōu)化
// 使用對象緩存
object.set({
objectCaching: true,
dirty: false
});
// 按需渲染
canvas.onlyRenderOnRequest = true;
canvas.requestRenderAll();
六、擴(kuò)展開發(fā)
1. 自定義對象
// 創(chuàng)建自定義箭頭對象
fabric.Arrow = fabric.util.createClass(fabric.Line, {
type: 'arrow',
initialize: function(points, options) {
options || (options = {});
this.callSuper('initialize', points, options);
},
_render: function(ctx) {
this.callSuper('_render', ctx);
// 繪制箭頭頭部
ctx.save();
const xDiff = this.x2 - this.x1;
const yDiff = this.y2 - this.y1;
const angle = Math.atan2(yDiff, xDiff);
ctx.translate(this.x2, this.y2);
ctx.rotate(angle);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(-10, -5);
ctx.lineTo(-10, 5);
ctx.closePath();
ctx.fillStyle = this.stroke;
ctx.fill();
ctx.restore();
}
});
// 添加到畫布
const arrow = new fabric.Arrow([50, 50, 200, 200], {
stroke: 'red',
strokeWidth: 3
});
canvas.add(arrow);
2. 自定義控件
// 添加自定義控制點(diǎn)
fabric.Object.prototype.controls.customControl = new fabric.Control({
x: 0.5,
y: -0.5,
actionHandler: function(eventData, transform, x, y) {
// 自定義處理邏輯
},
render: function(ctx, left, top, styleOverride, fabricObject) {
// 自定義渲染
},
cornerSize: 15
});
七、實(shí)際應(yīng)用場景
1. 圖形編輯器實(shí)現(xiàn)
// 工具欄功能實(shí)現(xiàn)
document.getElementById('btn-rect').addEventListener('click', () => {
const rect = new fabric.Rect({
width: 100,
height: 100,
fill: '#ff0000'
});
canvas.add(rect);
});
// 屬性面板綁定
document.getElementById('color-picker').addEventListener('change', (e) => {
const active = canvas.getActiveObject();
if (active) {
active.set('fill', e.target.value);
canvas.renderAll();
}
});
2. 圖像標(biāo)注系統(tǒng)
// 標(biāo)注工具
let drawingMode = 'rect';
let currentAnnotation = null;
canvas.on('mouse:down', (o) => {
if (drawingMode === 'rect') {
currentAnnotation = new fabric.Rect({
left: o.absolutePointer.x,
top: o.absolutePointer.y,
width: 0,
height: 0,
fill: 'rgba(255,0,0,0.2)',
stroke: 'red',
strokeWidth: 1,
selectable: true
});
canvas.add(currentAnnotation);
}
});
canvas.on('mouse:move', (o) => {
if (currentAnnotation) {
currentAnnotation.set({
width: o.absolutePointer.x - currentAnnotation.left,
height: o.absolutePointer.y - currentAnnotation.top
});
canvas.renderAll();
}
});
3. 流程圖設(shè)計器
// 連接線實(shí)現(xiàn)
class Connector extends fabric.Line {
constructor(from, to, options) {
super([from.left, from.top, to.left, to.top], options);
this.from = from;
this.to = to;
this.set({
stroke: '#666',
strokeWidth: 2,
selectable: false,
evented: false
});
}
update() {
this.set({
x1: this.from.left + this.from.width/2,
y1: this.from.top + this.from.height/2,
x2: this.to.left + this.to.width/2,
y2: this.to.top + this.to.height/2
});
}
}
// 自動更新連接線
canvas.on('object:moving', () => {
canvas.forEachObject(obj => {
if (obj instanceof Connector) {
obj.update();
}
});
});
Fabric.js 是一個功能全面且靈活的 Canvas 庫,通過其豐富的 API 和事件系統(tǒng),開發(fā)者可以構(gòu)建從簡單的圖形編輯器到復(fù)雜的可視化應(yīng)用的各類 Canvas 應(yīng)用。它的面向?qū)ο笤O(shè)計模式使得操作 Canvas 元素就像操作 DOM 元素一樣直觀,同時提供了專業(yè)級的圖形處理能力。
總結(jié)
到此這篇關(guān)于前端開源canvas工具庫Fabric.js的文章就介紹到這了,更多相關(guān)開源canvas工具庫Fabric.js內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解微信小程序網(wǎng)絡(luò)請求接口封裝實(shí)例
這篇文章主要介紹了微信小程序網(wǎng)絡(luò)請求接口封裝,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05
解決layui 復(fù)選框等內(nèi)置控件不顯示的問題
今天小編就為大家分享一篇解決layui 復(fù)選框等內(nèi)置控件不顯示的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08
JavaScript toUpperCase()方法使用詳解
這篇文章主要為大家詳細(xì)介紹了JavaScript toUpperCase()方法的使用技巧,感興趣的小伙伴們可以參考一下2016-08-08
layui在form表單頁面通過Validform加入簡單驗(yàn)證的方法
今天小編就為大家分享一篇layui在form表單頁面通過Validform加入簡單驗(yàn)證的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-09-09
js實(shí)現(xiàn)鼠標(biāo)拖拽div左右滑動
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)鼠標(biāo)拖拽div左右滑動,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-01-01
網(wǎng)絡(luò)復(fù)制內(nèi)容時常用的正則+editplus
有時侯我們在拷貝網(wǎng)頁上的內(nèi)容的時候,總是有一些,開頭的數(shù)字,需要替換掉2006-11-11

