使用fabric.js拖拽、旋轉、縮放圖片


什么是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

 

Fabricjs相關方法知識點(實踐)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM