javascript - How to drag and drop between canvases in Fabric.js - Stack Overflow

I understand Fabric.js have built-in support on drag-n-drop within the same canvas.How can we make it w

I understand Fabric.js have built-in support on drag-n-drop within the same canvas.

How can we make it work for multiple canvas?

Or from an non-canvas html element e.g. an image from a table?

I understand Fabric.js have built-in support on drag-n-drop within the same canvas.

How can we make it work for multiple canvas?

Or from an non-canvas html element e.g. an image from a table?

Share Improve this question edited Jan 23, 2014 at 15:28 kangax 39.2k13 gold badges100 silver badges135 bronze badges asked Jan 23, 2014 at 14:23 JohnJohn 2,1473 gold badges22 silver badges41 bronze badges 4
  • 2 There is no built-in support. You'll have to write your own code, and it's not straight-forward at all. Certainly not something that can be answered here. – Sergiu Paraschiv Commented Jan 23, 2014 at 14:26
  • 1 Hi. You need something like this? jsfiddle/ptCoder/aaFe7/9 – ptCoder Commented Jan 29, 2014 at 20:59
  • Other example: jsfiddle/uppzL/14 Check this: stackoverflow./questions/20311625/… – ptCoder Commented Jan 29, 2014 at 21:04
  • @ptCoder it seems like the jsfiddle link you referenced has errors in IE11 at least. Do you have another link that drags from canvas to canvas and drops in the exact spot the mouseup takes place? – whyoz Commented Apr 28, 2014 at 20:55
Add a ment  | 

2 Answers 2

Reset to default 5

Drag and drop between canvases is possible in Fabric.js, but involves some manipulation of private properties. For this reason it is not guaranteed to be functional with future versions of Fabric.js.

Working demo: https://jsfiddle/mmalex/kdbu9f3y/

Video capture: https://youtu.be/nXZgCmIrpqQ

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:

    //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./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. 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. Hard to explain, just follow the ments 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 plete 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!

Use

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

If event.e.clientY and event.e.clientX are outside the canvas, then:

var activeObject = canvas.getActiveObject();

Store in global dragImage var

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.

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 event:

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
{
    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. Works for text too but for text you must use dragImage=getActiveObject().clone() Any questions feel free to ask.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744258352a4565505.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信