什么是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="position:absolute;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> <html> <head> <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> <body> <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="position:absolute;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