• 使用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;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=" 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;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

  • 相关阅读:
    基于maven构建javaweb项目思路梳理及改进 在路上
    分圆多项式整理
    第03次作业栈和队列
    C语言第二次实验报告
    week01绪论作业
    第02次作业线性表
    C语言第一次实验报告
    工作流的问题
    无法使用Outlook 2003 Out Of Office Assisant
    刷机
  • 原文地址:https://www.cnblogs.com/rachelch/p/13964837.html
Copyright © 2020-2023  润新知