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

2024-01-05

据我所知,Fabric.js 内置了对同一画布内拖放操作的支持。

我们怎样才能让它适用于多个画布?

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


在 Fabric.js 中可以在画布之间进行拖放,但涉及对私有属性的一些操作。为此原因不保证它可以与 Fabric.js 的未来版本一起使用.

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

视频截取: https://youtu.be/nXZgCmIrpqQ https://youtu.be/nXZgCmIrpqQ

主要特征:

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

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

✓ 可以在不中断操作的情况下变换(镜像)掉落的图像。


Step 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- 订阅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);

Step 3– 解决方案的核心是在画布之间迁移对象而不中断鼠标操作。很难解释,直接看代码中的注释就可以了。

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

玩得开心!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 Fabric.js 中的画布之间拖放 的相关文章

随机推荐