【问题标题】:How to drag and drop between canvases in Fabric.js如何在 Fabric.js 中的画布之间拖放
【发布时间】:2014-02-14 03:48:27
【问题描述】:

我了解 Fabric.js 在同一画布中内置了拖放支持。

我们如何使它适用于多个画布?

或来自非画布 html 元素,例如表格中的图像?

【问题讨论】:

  • 没有内置支持。您必须编写自己的代码,而且这根本不是直截了当的。当然不是这里可以回答的问题。
  • 嗨。你需要这样的东西吗? jsfiddle.net/ptCoder/aaFe7/9
  • @ptCoder 似乎您引用的 jsfiddle 链接至少在 IE11 中存在错误。您是否有另一个链接可以从画布拖动到画布并放置在鼠标向上发生的确切位置?

标签: javascript html canvas fabricjs


【解决方案1】:

在 Fabric.js 中可以在画布之间拖放,但需要对私有属性进行一些操作。出于这个原因,不保证将来版本的 Fabric.js 可以正常工作

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

视频拍摄: https://youtu.be/nXZgCmIrpqQ

主要特点:

✓ 可以在任意数量的画布(不仅仅是两个)之间拖放,

✓ 可以不间断地在画布之间来回拖动,

✓ 可以在不中断操作的情况下转换(镜像)丢弃的图像。


第 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);

第 2 步 – 在两个画布上订阅 object:moving 事件,并观察对象中心何时穿过画布边界。当物体越过边界时,它必须是

  1. 从源画布中删除,
  2. 粘贴到目标画布中,
  3. 迁移内部画布转换(将单独说明)
    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);

第 3 步 – 解决方案的核心,在画布之间迁移对象而不中断鼠标操作。很难解释,就按照代码中的cmets来吧。

    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);
    };

玩得开心!

【讨论】:

  • 您说它适用于多个画布,但您在将数据从一个地方迁移到另一个地方时应用了硬编码画布。你能帮我一下吗?
【解决方案2】:

使用

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

如果 event.e.clientY 和 event.e.clientX 在画布之外,那么:

var activeObject = canvas.getActiveObject();

存储在全局dragImage var中

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

canvas.remove(activeObject);

然后在窗口鼠标移动事件中,您可以使用 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();
}
}

在窗口事件 mouseup 上,如果 dragImage != null 并且新坐标位于 fabric.js 画布内,则只需 newcanvas.add(dragImage)。

鼠标事件:

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 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
            );    
}

#dragimage 的 css:

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

我无能为力,但我在不到 30 分钟的时间内在我们的巨型相册编辑器上实现了这一点。也适用于文本,但对于文本,您必须使用 dragImage=getActiveObject().clone() 有任何问题欢迎随时提问。

【讨论】:

  • 有机会尝试一下吗?在两个滑稽的画布之间拖放?德克萨斯州肖恩
猜你喜欢
  • 2012-12-01
  • 2011-07-29
  • 1970-01-01
  • 2020-11-04
  • 2012-09-25
  • 2015-04-02
  • 2016-01-03
  • 2010-10-14
  • 1970-01-01
相关资源
最近更新 更多