> 技术文档 > 前端开源的canvas工具库Fabric.js

前端开源的canvas工具库Fabric.js

前端开源的canvas工具库Fabric.js

Fabric.js 是一个功能强大的 HTML5 Canvas 库,它通过面向对象的方式简化了 Canvas 操作,为开发者提供了丰富的图形操作功能和直观的 API 接口。

一、核心特性

1. 基础能力

  • 完整的对象模型:将画布元素抽象为对象(矩形、圆形、路径等)
  • 交互式操作:内置支持拖拽、旋转、缩放等交互
  • 丰富的图形类型:支持路径、图像、文本、组等
  • 动画系统:提供流畅的动画支持
  • 滤镜效果:内置多种图像滤镜
  • 序列化/反序列化:支持 JSON 导入导出

2. 高级功能

  • 自由绘制:铅笔、喷枪等绘画工具
  • SVG 支持:解析和渲染 SVG
  • 事件系统:完善的鼠标/触摸事件
  • 裁剪和蒙版:支持复杂裁剪操作
  • 自定义扩展:可扩展新的对象类型和功能

二、基本架构

1. 核心类结构

#mermaid-svg-fpxwL5NpOxnJWolC {font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-fpxwL5NpOxnJWolC .error-icon{fill:#552222;}#mermaid-svg-fpxwL5NpOxnJWolC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-fpxwL5NpOxnJWolC .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-fpxwL5NpOxnJWolC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-fpxwL5NpOxnJWolC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-fpxwL5NpOxnJWolC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-fpxwL5NpOxnJWolC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-fpxwL5NpOxnJWolC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-fpxwL5NpOxnJWolC .marker.cross{stroke:#333333;}#mermaid-svg-fpxwL5NpOxnJWolC svg{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-fpxwL5NpOxnJWolC g.classGroup text{fill:#9370DB;fill:#131300;stroke:none;font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-fpxwL5NpOxnJWolC g.classGroup text .title{font-weight:bolder;}#mermaid-svg-fpxwL5NpOxnJWolC .nodeLabel,#mermaid-svg-fpxwL5NpOxnJWolC .edgeLabel{color:#131300;}#mermaid-svg-fpxwL5NpOxnJWolC .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-fpxwL5NpOxnJWolC .label text{fill:#131300;}#mermaid-svg-fpxwL5NpOxnJWolC .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-fpxwL5NpOxnJWolC .classTitle{font-weight:bolder;}#mermaid-svg-fpxwL5NpOxnJWolC .node rect,#mermaid-svg-fpxwL5NpOxnJWolC .node circle,#mermaid-svg-fpxwL5NpOxnJWolC .node ellipse,#mermaid-svg-fpxwL5NpOxnJWolC .node polygon,#mermaid-svg-fpxwL5NpOxnJWolC .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-fpxwL5NpOxnJWolC .divider{stroke:#9370DB;stroke:1;}#mermaid-svg-fpxwL5NpOxnJWolC g.clickable{cursor:pointer;}#mermaid-svg-fpxwL5NpOxnJWolC g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-fpxwL5NpOxnJWolC g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-fpxwL5NpOxnJWolC .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-fpxwL5NpOxnJWolC .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-fpxwL5NpOxnJWolC .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-fpxwL5NpOxnJWolC .dashed-line{stroke-dasharray:3;}#mermaid-svg-fpxwL5NpOxnJWolC #compositionStart,#mermaid-svg-fpxwL5NpOxnJWolC .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-fpxwL5NpOxnJWolC #compositionEnd,#mermaid-svg-fpxwL5NpOxnJWolC .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-fpxwL5NpOxnJWolC #dependencyStart,#mermaid-svg-fpxwL5NpOxnJWolC .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-fpxwL5NpOxnJWolC #dependencyStart,#mermaid-svg-fpxwL5NpOxnJWolC .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-fpxwL5NpOxnJWolC #extensionStart,#mermaid-svg-fpxwL5NpOxnJWolC .extension{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-fpxwL5NpOxnJWolC #extensionEnd,#mermaid-svg-fpxwL5NpOxnJWolC .extension{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-fpxwL5NpOxnJWolC #aggregationStart,#mermaid-svg-fpxwL5NpOxnJWolC .aggregation{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-fpxwL5NpOxnJWolC #aggregationEnd,#mermaid-svg-fpxwL5NpOxnJWolC .aggregation{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-fpxwL5NpOxnJWolC .edgeTerminals{font-size:11px;}#mermaid-svg-fpxwL5NpOxnJWolC :root{--mermaid-font-family:\"trebuchet ms\",verdana,arial,sans-serif;}1*Canvas+width: Number+height: Number+add(...objects)+remove(...objects)+renderAll()+toJSON()+loadFromJSON()Object+left: Number+top: Number+angle: Number+opacity: Number+set(key, value)+animate(properties, options)RectCircleTextImagePathGroup

2. 对象继承体系

  • fabric.Object:所有图形基类
    • fabric.Rect:矩形
    • fabric.Circle:圆形
    • fabric.Triangle:三角形
    • fabric.Text:文本
    • fabric.Image:图像
    • fabric.Path:路径
    • fabric.Group:对象组
    • fabric.ActiveSelection:活动选择组

三、核心 API 详解

1. 画布初始化

// 创建画布实例const canvas = new fabric.Canvas(\'canvas-id\', { width: 800, // 画布宽度 height: 600, // 画布高度 backgroundColor: \'#f5f5f5\', // 背景色 selection: true, // 是否启用选择 preserveObjectStacking: true // 保持对象堆叠顺序});

2. 基本图形创建

// 创建矩形const rect = new fabric.Rect({ left: 100, top: 100, width: 200, height: 100, fill: \'red\', angle: 45, stroke: \'black\', strokeWidth: 2});// 创建圆形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);});

四、高级功能实现

1. 自由绘制实现

// 启用自由绘制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. 动画系统

// 简单动画rect.animate(\'angle\', 360, { duration: 1000, onChange: canvas.renderAll.bind(canvas), easing: fabric.util.ease.easeInOutQuad});// 复杂动画fabric.util.animate({ startValue: 0, endValue: 100, duration: 500, onChange: (value) => { circle.set(\'left\', value); canvas.renderAll(); }, onComplete: () => { console.log(\'动画完成\'); }});

3. 滤镜应用

// 创建图像对象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);});

五、性能优化技巧

1. 渲染优化

// 批量操作时暂停渲染canvas.renderOnAddRemove = false;// 执行多个操作...canvas.renderOnAddRemove = true;canvas.renderAll();// 使用 requestAnimationFramefunction animate() { requestAnimationFrame(() => { // 更新对象属性 canvas.renderAll(); animate(); });}

2. 内存管理

// 移除对象时彻底销毁canvas.remove(object);object = null;// 清理画布canvas.dispose();

3. 大数据量优化

// 使用对象缓存object.set({ objectCaching: true, dirty: false});// 按需渲染canvas.onlyRenderOnRequest = true;canvas.requestRenderAll();

六、扩展开发

1. 自定义对象

// 创建自定义箭头对象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. 自定义控件

// 添加自定义控制点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});

七、实际应用场景

1. 图形编辑器实现

// 工具栏功能实现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. 图像标注系统

// 标注工具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. 流程图设计器

// 连接线实现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 和事件系统,开发者可以构建从简单的图形编辑器到复杂的可视化应用的各类 Canvas 应用。它的面向对象设计模式使得操作 Canvas 元素就像操作 DOM 元素一样直观,同时提供了专业级的图形处理能力。