Fabric.js
是一个功能强大且操作简单的Javascript HTML5 canvas
工具库。
如果你需要用 canvas
做特效,那我推荐你使用 Fabric.js
,因为 Fabric.js
语法更加简单易用,而且还提供了很多交互类的 api
。
Fabric.js
简化了很多 Canvas
里的概念,代码看上去也更加语义化。
Fabric.js
能做什么?
可以打开 『Fabric.js 官网首页』 直接看例子,也可以看看 『Fabric.js Demos』 查看更炫酷的例子。
本文主要讲解 Fabric
提供的基础 画布 操作,包含一下内容
Fabric.js
js
设置画布参数本文在案例在 Vue3
环境下使用,不懂 Vue3
也没关系,因为不会涉及多少 Vue
的知识。
<script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="https://unpkg.com/fabric@4.6.0/dist/fabric.min.js"></script>
npm i fabric --save
基础版就是“起步”章节所说的那个例子。
<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 // 创建一个长方形 const rect = new fabric.Rect({ top: 100, // 距离容器顶部 100px left: 100, // 距离容器左侧 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 创建一个不可操作的画布 const canvas = new fabric.StaticCanvas('canvas') // 这里传入的是canvas元素的id // 创建一个长方形 const rect = new fabric.Rect({ top: 100, // 距离容器顶部 100px left: 100, // 距离容器左侧 100px width: 30, // 矩形宽度 30px height: 30, // 矩形高度 30px fill: 'red' // 填充 红色 }) canvas.add(rect) // 将矩形添加到 canvas 画布里 } onMounted(() => { init() }) </script>
创建不可交互的画布,其实只需把 new fabric.Canvas
改成 new fabric.StaticCanvas
即可。
<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, // 距离容器左侧 20px fill: 'pink' // 填充 粉色 }) canvas.add(circle) // 将圆形添加到 canvas 画布里 } onMounted(() => { init() }) </script>
new fabric.Canvas
的第二个参数是用来设置画布基础功能的。更多配置参数可以查看 『官方文档』。
<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') // 设置背景图 // 参数1:背景图资源(可以引入本地,也可以使用网络图) // 参数2:设置完背景图执行以下重新渲染canvas的操作,这样背景图就会展示出来了 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
这个很好懂,设置背景图片。
需要注意的是,在 Fabric.js
里使用 gif
只会渲染第一帧。
<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') // 设置背景图 // 参数1:背景图资源(可以引入本地,也可以使用网络图) // 参数2:设置完背景图执行以下重新渲染canvas的操作,这样背景图就会展示出来了 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 // 旋转背景图 } ) } onMounted(() => { init() }) </script>
setBackgroundImage
还有第三个参数,嘿嘿嘿没想到吧
第三个参数除了旋转,还可以设置 scaleX
、scaleY
之类的操作。
更多设置可以查看 『文档』 。
但这个例子存在一个问题,如果图片的尺寸没 canvas
容器大,就填不满,否则就溢出(只显示图片的局部)。
解决方案请看下一个案例。
<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 // 第一个参数:图片地址(可以是本地的,也可以是网络图) // 第二个参数:图片加载的回调函数 fabric.Image.fromURL( 'https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/27d1b4e5f8824198b6d51a2b1c2d0d75~tplv-k3u1fbpfcp-zoom-crop-mark:400:400:400:400.awebp', (img) => { // 设置背景图 canvas.setBackgroundImage( img, canvas.renderAll.bind(canvas), { scaleX: canvas.width / img.width, // 计算出图片要拉伸的宽度 scaleY: canvas.height / img.height // 计算出图片要拉伸的高度 } ) } ) } onMounted(() => { init() }) </script>
这个例子使用了 fabric.Image.fromURL
这个 api
来加载图片,第一个参数是图片地址,第二个参数是回调函数。
拿到图片的参数和画布的宽高进行计算,从而使图片充满全屏。
<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>
这个例子使用的图片尺寸是比较小的,所以在 setBackgroundColor
的第3个参数中设置了 repeat: 'repeat'
,表示重复渲染图片。
<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 }) ) // 设置覆盖图像的画布 canvas.setOverlayImage( // setOverlayImage(image, callback, optionsopt) jailCellBars, // 图片,script开头import进来的 canvas.renderAll.bind(canvas) ) } onMounted(() => { init() }) </script>
值得注意的2点:
canvas.setOverlayImage
代替原本的 canvas.setBackgroundImage
。png
,这样就能展示案例所示的效果,背景图叠在图案元素上面。🎁 本例所使用的图片地址