這個 19.4K 的 canvas 庫,功能很強大!
大廠技術(shù) 高級前端 Node進(jìn)階
點擊上方 程序員成長指北,關(guān)注公眾號
回復(fù)1,加入高級Node交流群
1導(dǎo)語
我們想在畫布上畫個基本的簡單形狀的時候,使用 Canvas 不會覺得有什么繁瑣。但當(dāng)畫布上需要任何形式的互動,繪制復(fù)雜的圖形和在特定情況需要改變圖片的時候,使用原生 canvas API 將會變得很困難。
而 Fabric 旨在解決這個問題。
Fabric.js 是一個強大而簡單的 Javascript HTML5 畫布庫 Fabric 在畫布元素之上提供交互式對象模型 Fabric 還具有 SVG-to-canvas(和 canvas-to-SVG)解析器

為了方便,下面我將通過 vue項目 為大家講解如何使用 Fabric
2. 安裝
yarn add fabric -S
#or
npm i fabric -S
也可以在 官網(wǎng) 下載最新 js 文件,通過 script 標(biāo)簽引入
3. 使用
<!-- html -->
<canvas id="canvas" width="500" height="500"></canvas>
3.1 繪制一個簡單的圖形
Fabric 提供了 7 種基礎(chǔ)形狀:
fabric.Circle (圓) fabric.Ellipse (橢圓) fabric.Line (線) fabric.Polyline (多條線繪制成圖形) fabric.triangle (三角形) fabric.Rect (矩形) fabric.Polygon (多邊形)
矩形
// js
//引入fabric
import { fabric } from "fabric";
// 創(chuàng)建一個fabric實例
let canvas = new fabric.Canvas("canvas"); //可以通過鼠標(biāo)方法縮小,旋轉(zhuǎn)
// or
// let canvas = new fabric.StaticCanvas("canvas");//沒有鼠標(biāo)交互的fabric對象
// 創(chuàng)建一個矩形對象
let rect = new fabric.Rect({
left: 200, //距離左邊的距離
top: 200, //距離上邊的距離
fill: "green", //填充的顏色
width: 200, //矩形寬度
height: 200, //矩形高度
});
// 將矩形添加到canvas畫布上
canvas.add(rect);
可以看到界面中填充了一個可以通過鼠標(biāo)放大縮小且可以旋轉(zhuǎn)的綠色矩形
通過對象的形式配置元素樣式,非常的方便!

圓形和三角形
// 創(chuàng)建一個圓形對象
let circle = new fabric.Circle({
left: 0, //距離左邊的距離
top: 0, //距離上邊的距離
fill: "red", //填充的顏色
radius: 50, //圓的半徑
});
// 創(chuàng)建一個三角形對象
let triangle = new fabric.Triangle({
left: 200, //距離左邊的距離
top: 0, //距離上邊的距離
fill: "blue", //填充的顏色
width: 100, //寬度
height: 100, //高度
});
// 將圖形形添加到canvas畫布上
canvas.add(circle, triangle);

我們可以通過以下屬性設(shè)置,決定是否可以對相關(guān)元素進(jìn)行交互
canvas.selection = false; // 禁止所有選中
rect.set("selectable", false); // 只是禁止這個矩形選中
3.2 繪制圖片
主要有通過 url 和 img 標(biāo)簽繪制兩種方式
//通過url繪制圖片
fabric.Image.fromURL(
//本地圖片需要通過require來引入,require("./xxx.jpeg")
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.thaihot.com.cn%2Fuploadimg%2Fico%2F2021%2F0711%2F1625982535739193.jpg&refer=http%3A%2F%2Fimg.thaihot.com.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1630940858&t=e1d24ff0a7eaeea2ff89cedf656a9374",
(img) => {
img.scale(0.5);
canvas.add(img);
}
);
//也可以通過標(biāo)簽繪制
let img = document.getElementById("img");
let image = new fabric.Image(img, {
left: 100,
top: 100,
opacity: 0.8,
});
canvas.add(image);

3.3 通過自定義的路徑繪制
在此之前我們需要了解幾個參數(shù)的含義
M : “move”移動到某點 L : “l(fā)ine”畫線 x,y C : “curve”曲線 A : “arc”弧 z : 閉合路徑(類似 PS 中的創(chuàng)建選區(qū))
let customPath = new fabric.Path("M 0 0 L 300 100 L 170 100 z");
customPath.set({
left: 100,
top: 100,
fill: "green",
});
canvas.add(customPath);

let customPath = new fabric.Path(
"M 0 0 L 300 100 L 170 100 L 70 300 L 20 200 C136.19,2.98,128.98,0,121.32,0 z"
);

可以看到通過路徑繪制,我們可以制作非常復(fù)雜的圖形(但是一般用不到,我們一般用它來解析 SVG 后拿到 path 復(fù)原圖形)
3.4 動畫
第一個參數(shù)是動畫的屬性,第二個參數(shù)是動畫的最終位置,第三個參數(shù)是一個可選的對象,指定動畫的細(xì)節(jié):持續(xù)時間,回調(diào),動效等。
第三個參數(shù)主要有
duration 默認(rèn)為 500ms。可以用來改變動畫的持續(xù)時間。 from 允許指定動畫屬性的起始值(如果我們不希望使用當(dāng)前值)。 onComplete 動畫結(jié)束之后的回調(diào)。 easing 動效函數(shù)。
絕對動畫
let canvas = new fabric.Canvas("canvas");
let rect = new fabric.Rect({
left: 400, //距離左邊的距離
top: 200, //距離上邊的距離
fill: "green", //填充的顏色
width: 200, //寬度
height: 200, //高度
});
rect.animate("left", 100, {
onChange: canvas.renderAll.bind(canvas),
duration: 1000,
});
canvas.add(rect);

相對動畫(第二個參數(shù)通過+=,-=等來決定動畫的最終效果)
rect.animate("left", "+=100", {
onChange: canvas.renderAll.bind(canvas),
duration: 1000,
});

rect.set({ angle: 45 });
rect.animate("angle", "-=90", {
onChange: canvas.renderAll.bind(canvas),
duration: 2000,
});

定義動畫的動效函數(shù)
默認(rèn)情況下,動畫使用“easeInSine”動效執(zhí)行。如果這不是你需要的,fabric 為我們提供了很多內(nèi)置動畫效果, fabric.util.ease 下有一大堆動效的選項。
常用的有easeOutBounce,easeInCubic,easeOutCubic,easeInElastic,easeOutElastic,easeInBounce 和 easeOutExpo等
rect.animate("left", 100, {
onChange: canvas.renderAll.bind(canvas),
duration: 1000,
easing: fabric.util.ease.easeOutBounce,
});

3.5 圖像濾鏡
目前 Fabric 為我們提供了以下內(nèi)置濾鏡
BaseFilter 基本過濾器 Blur 模糊 Brightness 亮度 ColorMatrix 顏色矩陣 Contrast 對比 Convolute 卷積 Gamma 伽瑪 Grayscale 灰度 HueRotation 色調(diào)旋轉(zhuǎn) Invert 倒置 Noise 噪音 Pixelate 像素化 RemoveColor 移除顏色 Resize 調(diào)整大小 Saturation 飽和
單個濾鏡
fabric.Image.fromURL(require("./aaa.jpeg"), (img) => {
img.scale(0.5);
canvas.add(img);
});
fabric.Image.fromURL(require("./aaa.jpeg"), (img) => {
img.scale(0.5);
// 添加濾鏡
img.filters.push(new fabric.Image.filters.Grayscale());
// 圖片加載完成之后,應(yīng)用濾鏡效果
img.applyFilters();
img.set({
left: 300,
top: 250,
});
canvas.add(img);
});

疊加濾鏡
“filters”屬性是一個數(shù)組,我們可以用數(shù)組方法執(zhí)行任何所需的操作:移除濾鏡(pop,splice,shift),添加濾鏡(push,unshift,splice),甚至可以組合多個濾鏡。當(dāng)我們調(diào)用 applyFilters 時,“filters”數(shù)組中存在的任何濾鏡將逐個應(yīng)用,所以讓我們嘗試創(chuàng)建一個既色偏又明亮(Brightness)的圖像。
fabric.Image.fromURL(require("./aaa.jpeg"), (img) => {
img.scale(0.5);
// 添加濾鏡
img.filters.push(
new fabric.Image.filters.Grayscale(),
new fabric.Image.filters.Sepia(), //色偏
new fabric.Image.filters.Brightness({ brightness: 0.2 }) //亮度
);
// 圖片加載完成之后,應(yīng)用濾鏡效果
img.applyFilters();
img.set({
left: 300,
top: 250,
});
canvas.add(img);
});

可以看到多個濾鏡的效果疊加顯示了,當(dāng)然 Fabric 還支持自定義濾鏡,在本篇文章點贊過 500 后我將更新 fabric 高級篇,感謝大家的支持~
3.6 顏色
無論你是使用十六進(jìn)制,RGB 或 RGBA 顏色,F(xiàn)abric 都能處理的很好
定義顏色
new fabric.Color("#f55");
new fabric.Color("#aa3123");
new fabric.Color("356333");
new fabric.Color("rgb(100,50,100)");
new fabric.Color("rgba(100, 200, 30, 0.5)");
顏色轉(zhuǎn)換
new fabric.Color('#f55').toRgb(); // "rgb(255,85,85)"
new fabric.Color('rgb(100,100,100)').toHex(); // "646464"
new fabric.Color('fff').toHex(); // "FFFFFF"
我們還可以用另一種顏色疊加,或?qū)⑵滢D(zhuǎn)換為灰度版本。
let redish = new fabric.Color("#f55");
let greenish = new fabric.Color("#5f5");
redish.overlayWith(greenish).toHex(); // "AAAA55"
redish.toGrayscale().toHex(); // "A1A1A1"
3.7 漸變
Fabric 通過 setGradient 方法支持漸變,在所有對象上定義。調(diào)用 setGradient('fill', { ... })就像設(shè)置一個對象的“fill”值一樣。
let circle = new fabric.Circle({
left: 100,
top: 100,
radius: 50
});
circle.setGradient("fill", {
// 漸變開始的位置
x1: 0,
y1: 0,
// 漸變結(jié)束的位置
x2: circle.width,
y2: 0,
//漸變的顏色
colorStops: {
// 漸變的范圍(0,0.1,0.3,0.5,0.75,1)0-1之間都可以
0: "red",
0.2: "orange",
0.4: "yellow",
0.6: "green",
0.8: "blue",
1: "purple"
},
});

3.8 文本
fabric.Text 對象對于文本,提供了比 canvas 更豐富的功能,包括:
支持多行 Multiline support 不幸的是,原生文本方法忽略了新建一行。 文本對齊 Text alignment 左,中,右。使用多行文本時很有用。 文本背景 Text background 背景也支持文本對齊。 文字裝飾 Text decoration 下劃線,上劃線,貫穿線。 行高 Line Height 在使用多行文本時有用。 字符間距 Char spacing 使文本更緊湊或更間隔。 子范圍 Subranges 將顏色和屬性應(yīng)用到文本對象的子對象中。 多字節(jié) Multibyte 支持表情符號。 交互式畫布編輯 On canvas editing 可以直接在畫布上鍵入文本。
let text = new fabric.Text(
"大家好~這里是前埔寨\n我是榮頂~\n一個要成為開發(fā)王的男人!",
{
left: 0,
top: 200,
fontFamily: "Comic Sans", //字體
fontSize: 50, //字號
fontWeight: 800, //字體粗細(xì),可以使用關(guān)鍵字(“normal”,“bold”)或數(shù)字(100,200,400,600,800)
shadow: "green 3px 3px 2px", //文字陰影,顏色,水平偏移,垂直偏移和模糊大小。
underline: true, //下劃線
linethrough: true, //刪除線
overline: true, //上劃線
fontStyle: "italic", //字體風(fēng)格,normal(正常)或italic(斜體)
stroke: "#c3bfbf", //描邊的顏色
strokeWidth: 1, //描邊的寬度
textAlign: "center", //文本對齊方式
lineHeight: 1.5, //行高
textBackgroundColor: "#91A8D0", //文本背景顏色
}
);
canvas.add(text);

3.9 事件
fabric 中通過 on 方法來初始化事件,off 方法用來刪除事件。
常用的事件有以下
“mouse:down” 鼠標(biāo)被按下 “object:add” 對象被添加 “after:render” 渲染完成
還有一大堆:
鼠標(biāo)事件:“mouse:down” ,“mouse:move”和“mouse:up...” 選擇相關(guān)的事件:“before:selection:cleared”, “selection:created”, 詳細(xì)的可以查看 官方文檔
canvas.on("mouse:down", function(options) {
canvas.clear();
let text = new fabric.Text("你點我啦~", {
left: 200,
top: 200,
});
canvas.add(text);
console.log(options.e.clientX, options.e.clientY);
});
canvas.on("mouse:up", function(options) {
this.text = "你沒點我0.0";
canvas.clear();
let text = new fabric.Text("你沒點我0.0", {
left: 200,
top: 200,
});
canvas.add(text);
console.log(options.e.clientX, options.e.clientY);
});

Fabric 允許將偵聽器直接附加到 canvas 畫布中的對象上。
let rect = new fabric.Rect({ width: 100, height: 50, fill: "green" });
rect.on("selected", function() {
console.log("哦吼~你選擇了我");
});
let circle = new fabric.Circle({ radius: 75, fill: "blue" });
circle.on("selected", function() {
console.log("哈哈哈~你選擇了我");
});
3.10自由繪畫
Fabric canvas 的 isDrawingMode 屬性設(shè)置為 true 即可實現(xiàn)自由繪制模式.
這樣畫布上的點擊和移動就會被立刻解釋為鉛筆或刷子。
let canvas = new fabric.Canvas("canvas");
canvas.isDrawingMode = true;
canvas.freeDrawingBrush.color = "blue";
canvas.freeDrawingBrush.width = 5;

4. 最后
很開心寫下這篇文章,它是我用來總結(jié)歸納 fabric 的知識點并且非常用心的一篇文章,希望這篇文章對你有所幫助,目前 fabric 在國內(nèi)還不是很火,但是 github 上已經(jīng)有 19.2k 的 star 了,也算是一個明星項目.我們?nèi)粘i_發(fā)經(jīng)常會用到 canvas,但是它的 api 對于處理復(fù)雜的業(yè)務(wù)邏輯會令人感到非常的勞累,所以我分享這篇文章,希望對大家有所幫助,點贊超過 500 我會更新 fabric.js 高級篇,感謝你的支持!
我組建了一個氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對Node.js學(xué)習(xí)感興趣的話(后續(xù)有計劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。

“分享、點贊、在看” 支持一波 
