Fabric.js 簡介
Fabric.js是一個(gè)功能強(qiáng)大且操作簡單的Javascript HTML5 canvas工具庫。
如果你需要用 canvas 做特效,那我推薦你使用 Fabric.js ,因?yàn)?Fabric.js 語法更加簡單易用,而且還提供了很多交互類的 api。
Fabric.js 簡化了很多 Canvas 里的概念,代碼看上去也更加語義化。
Fabric.js 能做什么?
可以打開 『Fabric.js 官網(wǎng)首頁』 直接看例子,也可以看看 『Fabric.js Demos』 查看更炫酷的例子。
本文簡介
本文主要講解 Fabric 提供的基礎(chǔ) 畫布 操作,包含一下內(nèi)容
- 安裝
Fabric.js - 畫布基礎(chǔ)版(可交互)
- 不可交互的畫布
- 在
js設(shè)置畫布參數(shù) - 使用背景圖
- 旋轉(zhuǎn)背景圖
- 拉伸背景圖
- 重復(fù)背景圖
- 重疊影像
本文在案例在 Vue3 環(huán)境下使用,不懂 Vue3 也沒關(guān)系,因?yàn)椴粫?huì)涉及多少 Vue 的知識(shí)。
相關(guān)鏈接
??本文所有案例倉庫地址 【歡迎Star,不定期更新?。。 ?/a>
動(dòng)手!
安裝 Fabric.js
CDN
<script src="https://unpkg.com/fabric@4.6.0/dist/fabric.min.js"></script>
npm
npm i fabric --save
基礎(chǔ)版(可交互)
基礎(chǔ)版就是“起步”章節(jié)所說的那個(gè)例子。
<template>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric' // 引入 fabric
function init() {
const canvas = new fabric.Canvas('canvas') // 這里傳入的是canvas元素的id
// 創(chuàng)建一個(gè)長方形
const rect = new fabric.Rect({
top: 100, // 距離容器頂部 100px
left: 100, // 距離容器左側(cè) 100px
width: 30, // 矩形寬度 30px
height: 30, // 矩形高度 30px
fill: 'red' // 填充 紅色
})
canvas.add(rect) // 將矩形添加到 canvas 畫布里
}
onMounted(() => {
init()
})
</script>
不可交互
<template>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric' // 引入 fabric
function init() {
// 使用 StaticCanvas 創(chuàng)建一個(gè)不可操作的畫布
const canvas = new fabric.StaticCanvas('canvas') // 這里傳入的是canvas元素的id
// 創(chuàng)建一個(gè)長方形
const rect = new fabric.Rect({
top: 100, // 距離容器頂部 100px
left: 100, // 距離容器左側(cè) 100px
width: 30, // 矩形寬度 30px
height: 30, // 矩形高度 30px
fill: 'red' // 填充 紅色
})
canvas.add(rect) // 將矩形添加到 canvas 畫布里
}
onMounted(() => {
init()
})
</script>
創(chuàng)建不可交互的畫布,其實(shí)只需把 new fabric.Canvas 改成 new fabric.StaticCanvas 即可。
在js設(shè)定畫布參數(shù)
<template>
<canvas id="canvas"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric' // 引入 fabric
function init() {
const canvas = new fabric.Canvas('canvas', {
width: 300, // 畫布寬度
height: 300, // 畫布高度
backgroundColor: '#eee' // 畫布背景色
})
// 圓形
const circle = new fabric.Circle({
radius: 30, // 圓的半徑
top: 20, // 距離容器頂部 20px
left: 20, // 距離容器左側(cè) 20px
fill: 'pink' // 填充 粉色
})
canvas.add(circle) // 將圓形添加到 canvas 畫布里
}
onMounted(() => {
init()
})
</script>
new fabric.Canvas 的第二個(gè)參數(shù)是用來設(shè)置畫布基礎(chǔ)功能的。更多配置參數(shù)可以查看 『官方文檔』。
使用背景圖
<template>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// 設(shè)置背景圖
// 參數(shù)1:背景圖資源(可以引入本地,也可以使用網(wǎng)絡(luò)圖)
// 參數(shù)2:設(shè)置完背景圖執(zhí)行以下重新渲染canvas的操作,這樣背景圖就會(huì)展示出來了
canvas.setBackgroundImage(
'https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/27d1b4e5f8824198b6d51a2b1c2d0d75~tplv-k3u1fbpfcp-zoom-crop-mark:400:400:400:400.awebp',
canvas.renderAll.bind(canvas)
)
}
onMounted(() => {
init()
})
</script>
setBackgroundImage 這個(gè)很好懂,設(shè)置背景圖片。
需要注意的是,在 Fabric.js 里使用 gif 只會(huì)渲染第一幀。
旋轉(zhuǎn)背景圖
<template>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// 設(shè)置背景圖
// 參數(shù)1:背景圖資源(可以引入本地,也可以使用網(wǎng)絡(luò)圖)
// 參數(shù)2:設(shè)置完背景圖執(zhí)行以下重新渲染canvas的操作,這樣背景圖就會(huì)展示出來了
canvas.setBackgroundImage(
'https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/27d1b4e5f8824198b6d51a2b1c2d0d75~tplv-k3u1fbpfcp-zoom-crop-mark:400:400:400:400.awebp',
canvas.renderAll.bind(canvas),
{
angle: 15 // 旋轉(zhuǎn)背景圖
}
)
}
onMounted(() => {
init()
})
</script>
setBackgroundImage 還有第三個(gè)參數(shù),嘿嘿嘿?zèng)]想到吧
第三個(gè)參數(shù)除了旋轉(zhuǎn),還可以設(shè)置 scaleX、scaleY 之類的操作。
更多設(shè)置可以查看 『文檔』 。
但這個(gè)例子存在一個(gè)問題,如果圖片的尺寸沒 canvas 容器大,就填不滿,否則就溢出(只顯示圖片的局部)。
解決方案請(qǐng)看下一個(gè)案例。
拉伸背景圖
<template>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// fabric.Image.fromURL:加載圖片的api
// 第一個(gè)參數(shù):圖片地址(可以是本地的,也可以是網(wǎng)絡(luò)圖)
// 第二個(gè)參數(shù):圖片加載的回調(diào)函數(shù)
fabric.Image.fromURL(
'https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/27d1b4e5f8824198b6d51a2b1c2d0d75~tplv-k3u1fbpfcp-zoom-crop-mark:400:400:400:400.awebp',
(img) => {
// 設(shè)置背景圖
canvas.setBackgroundImage(
img,
canvas.renderAll.bind(canvas),
{
scaleX: canvas.width / img.width, // 計(jì)算出圖片要拉伸的寬度
scaleY: canvas.height / img.height // 計(jì)算出圖片要拉伸的高度
}
)
}
)
}
onMounted(() => {
init()
})
</script>
這個(gè)例子使用了 fabric.Image.fromURL 這個(gè) api 來加載圖片,第一個(gè)參數(shù)是圖片地址,第二個(gè)參數(shù)是回調(diào)函數(shù)。
拿到圖片的參數(shù)和畫布的寬高進(jìn)行計(jì)算,從而使圖片充滿全屏。
重復(fù)背景圖
<template>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
canvas.setBackgroundColor({
source: 'https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/27d1b4e5f8824198b6d51a2b1c2d0d75~tplv-k3u1fbpfcp-zoom-crop-mark:40:40:40:40.awebp',
repeat: 'repeat'
}, canvas.renderAll.bind(canvas))
}
onMounted(() => {
init()
})
</script>
這個(gè)例子使用的圖片尺寸是比較小的,所以在 setBackgroundColor 的第3個(gè)參數(shù)中設(shè)置了 repeat: 'repeat' ,表示重復(fù)渲染圖片。
重疊影象
<template>
<canvas width="400" height="375" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
import jailCellBars from '@/assets/images/jail_cell_bars.png' // 引入背景圖
function init() {
const canvas = new fabric.Canvas('canvas')
canvas.add(
new fabric.Circle({
radius: 30, // 圓形半徑
fill: '#f55',
top: 70,
left: 70
})
)
// 設(shè)置覆蓋圖像的畫布
canvas.setOverlayImage( // setOverlayImage(image, callback, optionsopt)
jailCellBars, // 圖片,script開頭import進(jìn)來的
canvas.renderAll.bind(canvas)
)
}
onMounted(() => {
init()
})
</script>
值得注意的2點(diǎn):
- 使用
canvas.setOverlayImage代替原本的canvas.setBackgroundImage。 - 所使用的圖片最好是帶透明層的
png,這樣就能展示案例所示的效果,背景圖疊在圖案元素上面。












