简体   繁体   English

如何在Fabric.js中的画布之间拖放

[英]How to drag and drop between canvases in Fabric.js

I understand Fabric.js have built-in support on drag-n-drop within the same canvas. 我理解Fabric.js在同一个画布中内置了对drag-n-drop的支持。

How can we make it work for multiple canvas? 我们怎样才能使它适用于多个画布?

Or from an non-canvas html element eg an image from a table? 或者从非画布html元素,例如表格中的图像?

Use 使用

 canvas.observe("object:moving", function (event) {});

If event.e.clientY and event.e.clientX are outside the canvas, then: 如果event.e.clientY和event.e.clientX在画布外,则:

var activeObject = canvas.getActiveObject();

Store in global dragImage var 存储在全局dragImage变量中

activeObject.clone(function (c) { dragImage = c; });

canvas.remove(activeObject);

Then in window mouse move event you can place an img with src = dragImage.src and follow the cursor. 然后在窗口鼠标移动事件中,您可以使用src = dragImage.src放置一个img并按照光标。

function mousemove(e){
if (dragImage != null) {
    $("#dragimage").show();
    $("#dragimage").css("left", e.clientX); 
    $("#dragimage").css("top", e.clientY);
    return;
}else{
$("#dragimage").hide();
}
}

On a window event mouseup, if dragImage != null and new coordinates are inside a fabric.js canvas, just newcanvas.add(dragImage). 在窗口事件mouseup上,如果dragImage!= null并且新坐标位于fabric.js画布内,则只需newcanvas.add(dragImage)。

mouseup event: mouseup事件:

if (dragImage != null) {
            $([canvas, canvas2]).each(function (i, v) {
                if (Intersect([event.clientX, event.clientY],$(v.wrapperEl))) {
                    dragImage.left = event.clientX - $(v.wrapperEl).offset().left;
                    dragImage.top = event.clientY - $(v.wrapperEl).offset().top;
                    v.add(dragImage);
                }              

            });

            dragImage = null;
        }

Helper Intersect function: 辅助相交功能:

function Intersect(point, element) {
    return (      point[0] > element.offset().left
               && point[0] < element.offset().left + element.width()
               && point[1] < element.offset().top + element.height()
               && point[1] > element.offset().top
            );    
}

css for #dragimage: #dragimage的CSS:

#dragimage
{
    opacity:0.5;
    max-width:100px;
    max-height:200px;
    position:fixed;
    top:0px;
    left:0px;
    z-index:90000;
}

I can't do a fiddle but i implemented this on our mega huge photo album editor in less than 30 minutes. 我不能做一个小提琴,但我在不到30分钟的时间内在我们的巨型相册编辑器上实现了这一点。 Works for text too but for text you must use dragImage=getActiveObject().clone() Any questions feel free to ask. 也适用于文本,但对于文本,你必须使用dragImage = getActiveObject()。clone()任何问题都可以随意提问。

Drag and drop between canvases is possible in Fabric.js, but involves some manipulation of private properties. 可以在Fabric.js中拖放画布,但需要对私有属性进行一些操作。 For this reason it is not guaranteed to be functional with future versions of Fabric.js . 因此,不保证Fabric.js的未来版本可以正常运行

Working demo: https://jsfiddle.net/mmalex/kdbu9f3y/ 工作演示: https //jsfiddle.net/mmalex/kdbu9f3y/

Video capture: https://youtu.be/nXZgCmIrpqQ 视频捕获: https //youtu.be/nXZgCmIrpqQ

在fabric.js中的画布之间拖放

Key features: 主要特征:

✓ can drag and drop between any number of canvases (not only two), ✓可以在任意数量的画布(不仅仅是两个)之间拖放,

✓ can drag back and forth between canvases without interruption, ✓可以不间断地在画布之间来回拖动,

✓ can transform (mirror) dropped image without interruption of manipulation. ✓可以在不中断操作的情况下转换(镜像)丢弃的图像。


Step 1 – prepare canvases, load images, arrange everything for demo: 第1步 - 准备画布,加载图像,安排演示的所有内容:

    //create two canvases
    var canvas0El = document.getElementById("c0");
    canvas0El.width = canvas0El.offsetWidth;
    canvas0El.height = canvas0El.parentElement.offsetHeight;

    var canvas1El = document.getElementById("c1");
    canvas1El.width = canvas1El.offsetWidth;
    canvas1El.height = canvas1El.parentElement.offsetHeight;

    var canvas0 = new fabric.Canvas('c0');
    canvas0.setBackgroundColor('rgba(19, 19, 19, 0.25)');
    canvas0.renderAll();

    var canvas1 = new fabric.Canvas('c1');
    canvas1.setBackgroundColor('rgba(92, 18, 18, 0.25)');
    canvas1.renderAll();

    // add loaded image on left canvas
    var onImageLoaded = function(oImg) {
        oImg.originX = "center";
        oImg.originY = "center";

        oImg.left = this.x;
        oImg.top = this.y;

        canvas0.add(oImg);
        oImg.canvas = canvas0;
        imgArrow = oImg;
    };

    var config = { crossOrigin: 'anonymous' };

    var baseUrl = "http://mbnsay.com/rayys/images";
    var url0 = baseUrl + "/arrow-right-green.png";
    var url1 = baseUrl + "/arrow-right-icon.png";
    var url2 = baseUrl + "/arrow-right-blue.png";

    // load some images
    fabric.Image.fromURL(url0, onImageLoaded.bind({ x: 56,  y: 96 }), config);
    fabric.Image.fromURL(url0, onImageLoaded.bind({ x: 156, y: 96 }), config);

    fabric.Image.fromURL(url1, onImageLoaded.bind({ x: 56,  y: 2*96 }), config);
    fabric.Image.fromURL(url1, onImageLoaded.bind({ x: 156, y: 2*96 }), config);

    fabric.Image.fromURL(url2, onImageLoaded.bind({ x: 56,  y: 3*96 }), config);
    fabric.Image.fromURL(url2, onImageLoaded.bind({ x: 156, y: 3*96 }), config);

Step 2 – subscribe object:moving events on both canvases, and watch when object center crossing the canvas border. 第2步 - 订阅object:moving在两个画布上object:moving事件,并在对象中心穿过画布边框时观察。 When object crosses the border, it has to be 当物体穿过边界时,它必须是

  1. remove from source canvas, 从源画布中删除,
  2. paste into destination canvas, 粘贴到目标画布,
  3. migrate internal canvas transformations (will be explained separately) 迁移内部画布转换(将单独解释)
    var onObjectMoving = function(p) {
        var viewport = p.target.canvas.calcViewportBoundaries();

        if (p.target.canvas === canvas0) {
            if (p.target.left > viewport.br.x) {
                console.log("Migrate: left -> center");
                migrateItem(canvas0, canvas1, p.target);
                return;
            }
        }
        if (p.target.canvas === canvas1) {
            if (p.target.left < viewport.tl.x) {
                console.log("Migrate: center -> left");
                migrateItem(canvas1, canvas0, p.target);
                return;
            }
        }
    };

    canvas0.on("object:moving", onObjectMoving);
    canvas1.on("object:moving", onObjectMoving);

Step 3 – The core of the solution, migrate object between canvases not interrupting mouse manipulations. 第3步 - 解决方案的核心,在不影响鼠标操作的画布之间迁移对象。 Hard to explain, just follow the comments in code. 很难解释,只需按照代码中的注释。

    var migrateItem = function(fromCanvas, toCanvas, pendingImage) {
        // Just drop image from old canvas
        fromCanvas.remove(pendingImage);

        // We're going to trick fabric.js,
        // so we keep internal transforms of the source canvas, 
        // in order to inject it into destination canvas.
        var pendingTransform = fromCanvas._currentTransform;
        fromCanvas._currentTransform = null;

        // Make shortcuts for fabric.util.removeListener and fabric.util.addListener
        var removeListener = fabric.util.removeListener;
        var addListener = fabric.util.addListener;

        // Re-arrange subscriptions for source canvas
        {
            removeListener(fabric.document, 'mouseup', fromCanvas._onMouseUp);
            removeListener(fabric.document, 'touchend', fromCanvas._onMouseUp);

            removeListener(fabric.document, 'mousemove', fromCanvas._onMouseMove);
            removeListener(fabric.document, 'touchmove', fromCanvas._onMouseMove);

            addListener(fromCanvas.upperCanvasEl, 'mousemove', fromCanvas._onMouseMove);
            addListener(fromCanvas.upperCanvasEl, 'touchmove', fromCanvas._onMouseMove, {
                passive: false
            });

            if (isTouchDevice) {
                // Wait 500ms before rebinding mousedown to prevent double triggers
                // from touch devices
                var _this = fromCanvas;
                setTimeout(function() {
                    addListener(_this.upperCanvasEl, 'mousedown', _this._onMouseDown);
                }, 500);
            }
        }

        // Re-arrange subscriptions for destination canvas
        {
            addListener(fabric.document, 'touchend', toCanvas._onMouseUp, {
                passive: false
            });
            addListener(fabric.document, 'touchmove', toCanvas._onMouseMove, {
                passive: false
            });

            removeListener(toCanvas.upperCanvasEl, 'mousemove', toCanvas._onMouseMove);
            removeListener(toCanvas.upperCanvasEl, 'touchmove', toCanvas._onMouseMove);

            if (isTouchDevice) {
                // Unbind mousedown to prevent double triggers from touch devices
                removeListener(toCanvas.upperCanvasEl, 'mousedown', toCanvas._onMouseDown);
            } else {
                addListener(fabric.document, 'mouseup', toCanvas._onMouseUp);
                addListener(fabric.document, 'mousemove', toCanvas._onMouseMove);
            }
        }

        // We need this timer, because we want Fabric.js to complete pending render
        // before we inject, because it causes some unpleasant image jumping.
        setTimeout(function() {
            // Add image to destination canvas,
            pendingImage.scaleX *= -1;
            pendingImage.canvas = toCanvas;
            pendingImage.migrated = true;
            toCanvas.add(pendingImage);

            // and inject transforms from source canvas
            toCanvas._currentTransform = pendingTransform;

            // as we have mirrored the image, we mirror transforms too
            toCanvas._currentTransform.scaleX *= -1;
            toCanvas._currentTransform.original.scaleX *= -1;

            // finally don't forget to make pasted object selected
            toCanvas.setActiveObject(pendingImage);
        }, 10);
    };

Have fun! 玩得开心!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM