什么是Fabric.js?
Fabric.js
是一个强大的H5 canvas框架,在原生canvas之上提供了交互式对象模型,通过简洁的api就可以在画布上进行丰富的操作。
Fabric.js有什么功能?
使用Fabric.js,你可以在画布上创建和填充对象; 比如简单的几何形状 - 矩形,圆形,椭圆形,多边形,自定义图片或由数百或数千个简单路径组成的更复杂的形状。 另外,还可以使用鼠标缩放,移动和旋转这些对象; 修改它们的属性 - 颜色,透明度,z-index等。也可以将画布上的对象进行组合。
npm 安装
npm install fabric --save
通过cdn引用
<script src="https://cdn.bootcdn.net/ajax/libs/fabric.js/4.2.0/fabric.js"></script>
首先在 html 页面中写一个800 x 800的 canvas 标签,这里不写宽高也行,后面可以通过js来设置宽高
<canvas id="canvas" width="800" height="800"></canvas>
初始化fabric的 canvas 对象,创建一个卡片(后面都用 canvas 表示画布对象)
const canvas = new fabric.Canvas('canvas');
// ...这里可以写canvas对象的一些配置,后面将会介绍
// 如果<canvas>标签没设置宽高,可以通过js动态设置
canvas.setWidth(350);
canvas.setHeight(200);
这样就创建了一个基本的画布。
开始其他操作
向画布添加图层对象
fabric.js提供了很多对象,除了基本的
Rect、Circle、Line、Ellipse、Polygon、Polyline、Triangle
对象外,还有如
Image、Textbox、Group
等更高级的对象,这些都是继承自 Fabric 的
Object对象
。
下面我就介绍如何添加图片和文字,其他对象大同小异
* 如何向画布添加一个Image对象?
//
方式一 (通过img元素添加)
const imgElement = document.getElementById('img'
);
const imgInstance
=
new
fabric.Image(imgElement, {
left:
100,
//
图片相对画布的左侧距离
top: 100,
//
图片相对画布的顶部距离
angle: 30,
//
图片旋转角度
opacity: 0.85,
//
图片透明度
//
这里可以通过scaleX和scaleY来设置图片绘制后的大小,这里为原来大小的一半
scaleX: 0.5
,
scaleY:
0.5
//
添加对象后, 如下图
canvas.add(imgInstance);
// 方式二(通过图片路径添加)
fabric.Image.fromURL('img/2.png', (img) => {
img.set({
left: 100, // 图片相对画布的左侧距离
top: 100, // 图片相对画布的顶部距离
angle: 30, // 图片旋转角度
opacity: 0.85, // 图片透明度
// 这里可以通过scaleX和scaleY来设置图片绘制后的大小,这里为原来大小的一半
scaleX: 0.5,
scaleY: 0.5
// 添加对象
canvas.add(img);
设置图层控件的样式
imgInstance.set({
transparentCorners: false,
cornerColor: 'blue',
cornerStrokeColor: 'red',
borderColor: 'red',
cornerSize: 12,
padding: 10,
cornerStyle: 'circle',
borderDashArray: [3, 3]
导出下载图片
<button onclick="downloadFabric(canvas, new Date().getTime())">导出</button>
function download(url,name){
$('<a>').attr({href:url,download:name})[0].click();
function downloadFabric(canvas,name){
download(canvas.toDataURL(),name+'.png');
设置画布背景
fabric.Image.fromURL('img/forest.jpg', (img) => {
img.set({
// 通过scale来设置图片大小,这里设置和画布一样大
scaleX: canvas.width / img.width,
scaleY: canvas.height / img.height,
// 设置背景
canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas));
canvas.renderAll();
鼠标滚动缩放
var zoom;
canvas.on({
// 鼠标滚动缩放
"mouse:wheel": (e) => {
zoom = (event.deltaY > 0 ? -0.1 : 0.1) + canvas.getZoom();
zoom = Math.max(0.1, zoom); //最小为原来的1/10
zoom = Math.min(3, zoom); //最大是原来的3倍
zoomPoint = new fabric.Point(400, 400); // 中心点
canvas.zoomToPoint(zoomPoint, zoom);
鼠标拖动旋转
canvas.on({
// 鼠标旋转
"object:rotating": (e) => {
tag.style.display = 'block';
var offsetX = e.e.offsetX;
var offsetY = e.e.offsetY;
tag.style.left = offsetX + 30 + 'px'; // 离鼠标太近,可能会出现抖动,闪现
tag.style.top = offsetY + 30 + 'px';
"object:rotated": (e) => {
tag.style.display = 'none';
画布状态记录
框架提供了如 toJSON 和 loadFromJSON 方法,作用分别为导出当前画布的 json 信息,加载json画布信息来还原画布状态。
// 导出当前画布信息
const currState = canvas.toJSON();
// 加载画布信息
canvas.loadFromJSON(lastState, () => {
card.renderAll();
删除某个图层
<img src="img/close.svg" id="deleteBtn" style="top: 0px;left: 0px;cursor:pointer;width:20px;height:20px;display: none;"/>
// 删除某个图层
var deleteBtn = document.getElementById('deleteBtn');
function addDeleteBtn(x, y){
deleteBtn.style.display ='none';
deleteBtn.style.left = x + 30 + 'px';
deleteBtn.style.top = y - 15 + 'px';
deleteBtn.style.display ='block';
canvas.on('selection:created', function(e){
addDeleteBtn(e.target.lineCoords.tr.x, e.target.lineCoords.tr.y);
canvas.on('selection:updated', function(e){
addDeleteBtn(e.target.lineCoords.tr.x, e.target.lineCoords.tr.y);
canvas.on('mouse:down', function(e){
if(!canvas.getActiveObject()){
deleteBtn.style.display ='none';
canvas.on('object:modified', function(e){
addDeleteBtn(e.target.lineCoords.tr.x, e.target.lineCoords.tr.y);
canvas.on('object:scaling', function(e){
deleteBtn.style.display ='none';
canvas.on('object:moving', function(e){
deleteBtn.style.display ='none';
canvas.on('object:rotating', function(e){
deleteBtn.style.display ='none';
canvas.on('mouse:wheel', function(e){
deleteBtn.style.display ='none';
$(document).on('click',"#deleteBtn", function(){
if(canvas.getActiveObject()){
canvas.remove(canvas.getActiveObject());
deleteBtn.style.display ='none';
效果如下:
<!DOCTYPE html>
<meta charset="UTF-8">
<title></title>
<style>
*{padding: 0;margin: 0;}
.backgrounds{
display: flex;
.backgrounds img{
width: 200px;
height: 200px;
#CanvasContainer {
width: 270px;
height: 519px;
margin-left: 15px;
#Canvas {
overflow: hidden;
.tag{
position:
absolute;
z-index: 15;
padding: 0 5px;
min-width: 48px;
height: 16px;
line-height: 16px;
text-align: center;
font-size: 12px;
color: #505050;
border: 1px solid #fff;
background: hsla(0,0%,86.3%,.8);
border-radius: 10px;
-webkit-border-radius: 10px;
display: none;
</style>
</head>
<div id="Backgrounds" class="backgrounds">
<img src="img/shoe1.jpg" alt="" id="img1"/>
<img src="img/shoe2.jpg" alt="" id="img2"/>
<img src="img/shoe3.png" alt="" id="img3"/>
</div>
<div class="container" style="position: relative;">
<div id="CanvasContainer" style="width: 800px;height: 800px;border: 1px solid #ccc;">
<canvas id="Canvas" width="800" height="800"></canvas>
</div>
<div class="tag" id="tag">3</div>
<img src="img/close.svg" id="deleteBtn" style="top: 0px;left: 0px;cursor:pointer;width:20px;height:20px;display: none;"/>
</div>
<button onclick="downloadFabric(canvas, new Date().getTime())">导出</button>
<button onclick="unload()">离开</button>
<script src="fabric.js"></script>
<script src="js/jquery.min.js"></script>
<script>
var canvas = new fabric.Canvas('Canvas');
$(document).ready(function () {
$("#Backgrounds img").click(function () {
var getId = $(this).attr("id");
var imgElement = document.getElementById(getId);
var imgInstance = new fabric.Image(imgElement, {
left: 0,
top: 0
imgInstance.set({
transparentCorners: false,
cornerColor: 'black',
cornerStrokeColor: 'black',
borderColor: '#686666',
cornerSize: 12,
padding: 10,
cornerStyle: 'circle',
borderDashArray: [3, 3],
canvas.add(imgInstance);
// 设置画布背景
fabric.Image.fromURL('img/forest.jpg', (img) => {
img.set({
// 通过scale来设置图片大小,这里设置和画布一样大
scaleX: canvas.width / img.width,
scaleY: canvas.height / img.height,
// 设置背景
canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas));
canvas.renderAll();
// 导出下载图片
function download(url,name){
$('<a>').attr({href:url,download:name})[0].click();
function downloadFabric(canvas,name){
// 导出合并后的图片
download(canvas.toDataURL(),name+'.png');
// 导出单独的图片
// download(canvas._objects[0].toDataURL(),name+'.png');
var tag = document.getElementById('tag');
var zoom,zoomPoint;
canvas.on({
// 鼠标滚动缩放
"mouse:wheel": (e) => {
zoom = (event.deltaY > 0 ? -0.1 : 0.1) + canvas.getZoom();
zoom = Math.max(0.1, zoom); //最小为原来的1/10
zoom = Math.min(3, zoom); //最大是原来的3倍
// zoomPoint = new fabric.Point(e.pointer.x, e.pointer.y);
zoomPoint = new fabric.Point(400, 400); // 中心点
canvas.zoomToPoint(zoomPoint, zoom);
// 鼠标旋转
"object:rotating": (e) => {
tag.style.display = 'block';
var offsetX = e.e.offsetX;
var offsetY = e.e.offsetY;
tag.style.left = offsetX + 30 + 'px'; // 离鼠标太近,可能会出现抖动,闪现
tag.style.top = offsetY + 30 + 'px';
"object:rotated": (e) => {
tag.style.display = 'none';
// 离开页面,保存当前的画布信息
function unload(){
// 导出当前画布信息
const currState = canvas.toJSON();
sessionStorage.setItem('img', JSON.stringify(currState));
sessionStorage.setItem('zoomObj',JSON.stringify({zm: zoom, zmpoint: zoomPoint}));
// 刷新,恢复之前的画布信息
var sessionImg = sessionStorage.getItem('img');
var lastState = sessionImg? JSON.parse(sessionImg): '';
var zoomObj
= sessionStorage.getItem('zoomObj')? JSON.parse(sessionStorage.getItem('zoomObj')): '';
// 加载画布信息
canvas.loadFromJSON(lastState, () => {
// 设置缩放点
zoomPoint = zoomObj.zmpoint;
zoom = zoomObj.zm;
canvas.zoomToPoint({x: zoomPoint.x,y: zoomPoint.y}, zoom);
// 给每一个图层设置边框圆角样式 刷新后重绘,需要重新设置之前的一些样式
var objects = canvas._objects;
if(objects.length > 0){
objects.map(item => {
item.set({
transparentCorners: false,
cornerColor: 'black',
cornerStrokeColor: 'black',
borderColor: '#686666',
cornerSize: 12,
padding: 10,
cornerStyle: 'circle',
borderDashArray: [3, 3],
// 重绘
canvas.renderAll();
// 删除某个图层
var deleteBtn = document.getElementById('deleteBtn');
function addDeleteBtn(x, y){
deleteBtn.style.display ='none';
deleteBtn.style.left = x + 30 + 'px';
deleteBtn.style.top = y - 15 + 'px';
deleteBtn.style.display ='block';
canvas.on('selection:created', function(e){
addDeleteBtn(e.target.lineCoords.tr.x, e.target.lineCoords.tr.y);
canvas.on('selection:updated', function(e){
addDeleteBtn(e.target.lineCoords.tr.x, e.target.lineCoords.tr.y);
canvas.on('mouse:down', function(e){
if(!canvas.getActiveObject()){
deleteBtn.style.display ='none';
canvas.on('object:modified', function(e){
addDeleteBtn(e.target.lineCoords.tr.x, e.target.lineCoords.tr.y);
canvas.on('object:scaling', function(e){
deleteBtn.style.display ='none';
canvas.on('object:moving', function(e){
deleteBtn.style.display ='none';
canvas.on('object:rotating', function(e){
deleteBtn.style.display ='none';
canvas.on('mouse:wheel', function(e){
deleteBtn.style.display ='none';
$(document).on('click',"#deleteBtn", function(){
if(canvas.getActiveObject()){
canvas.remove(canvas.getActiveObject());
deleteBtn.style.display ='none';
</script>
</body>
</html>
fabricjs使用笔记
参考文章:使用Fabric.js玩转canvas
Fabricjs相关方法知识点(实践)