Drag And Drop Image to Canvas (FabricJS)

2019-03-31 22:49发布

The Problem
I want to do this with an image instead of a canvas object. Meaning you have to add the thing you want to add TO AND AS A PART of the canvas before you can add it. The images are actually part of the website so it doesn't need to do some intricate stuff. This code I found here only works for when it's an object not an actual element. And by the way I'm using FabricJS just to let you know that I'm not using the default HTML5 canvas stuff.

As for any alternatives that are possibly going to work without using my current code. Please do post it down below in the comments or in the answers. I would really love to see what you guys got in mind.

Summary
Basically I want to be able to drag and drop images through the canvas while retaining the mouse cursor position. For example if I drag and image and the cursor was at x: 50 y: 75 it would drop the image to that exact spot. Just like what the code I found does. But like the problem stated the CODE uses an object for you to drag it to the canvas then it clones it. I want this functionality using just plain old elements. E.g: <img>.


THE CODE - JsFiddle

window.canvas = new fabric.Canvas('fabriccanvas');
var edgedetection = 8; //pixels to snap
canvas.selection = false;

window.addEventListener('resize', resizeCanvas, false);

function resizeCanvas() {
    canvas.setHeight(window.innerHeight);
    canvas.setWidth(window.innerWidth);
    canvas.renderAll();
}

// resize on init
resizeCanvas();

//Initialize Everything
init();

function init(top, left, width, height, fill) {

    var bg = new fabric.Rect({
        left: 0,
        top: 0,
        fill:  "#eee",
        width: window.innerWidth,
        height: 75,    
        lockRotation: true,
        maxHeight: document.getElementById("fabriccanvas").height,
        maxWidth: document.getElementById("fabriccanvas").width,
        selectable: false,
    });

    var squareBtn = new fabric.Rect({
        top: 10,
        left: 18,
        width: 40,
        height: 40,
        fill: '#af3',
        lockRotation: true,
        originX: 'left',
        originY: 'top',
        cornerSize: 15,
        hasRotatingPoint: false,
        perPixelTargetFind: true,
    });

    var circleBtn = new fabric.Circle({
        radius: 20,
        fill: '#f55',
        top: 10,
        left: 105,
    });

    var triangleBtn = new fabric.Triangle({
        width: 40, 
        height: 35, 
        fill: 'blue', 
        top: 15,
        left: 190,
    });

    var sqrText = new fabric.IText("Add Square", {
        fontFamily: 'Indie Flower',
        fontSize: 14,
        fontWeight: 'bold',
        left: 6,
        top: 50,
        selectable: false,
    });

    var cirText = new fabric.IText("Add Circle", {
        fontFamily: 'Indie Flower',
        fontSize: 14,
        fontWeight: 'bold',
        left: 95,
        top: 50,
        selectable: false,
    });

    var triText = new fabric.IText("Add Triangle", {
        fontFamily: 'Indie Flower',
        fontSize: 14,
        fontWeight: 'bold',
        left: 175,
        top: 50,
        selectable: false,
    });

    var shadow = {
        color: 'rgba(0,0,0,0.6)',
        blur: 3,    
        offsetX: 0,
        offsetY: 2,
        opacity: 0.6,
        fillShadow: true, 
        strokeShadow: true 
    };

    window.canvas.add(bg);
    bg.setShadow(shadow);
    window.canvas.add(squareBtn);
    window.canvas.add(circleBtn);
    window.canvas.add(triangleBtn);
    window.canvas.add(sqrText);
    window.canvas.add(cirText);
    window.canvas.add(triText);

    canvas.forEachObject(function (e) {
        e.hasControls = e.hasBorders = false; //remove borders/controls
    });

    function draggable(object) {
        object.on('mousedown', function() {
            var temp = this.clone();
            temp.set({
                hasControls: false,
                hasBorders: false,
            });
            canvas.add(temp);
            draggable(temp);
        });
        object.on('mouseup', function() {
            // Remove an event handler
            this.off('mousedown');

            // Comment this will let the clone object able to be removed by drag it to menu bar
            // this.off('mouseup');

            // Remove the object if its position is in menu bar
            if(this.top<=75) {
                canvas.remove(this);
            }
        });
    }

    draggable(squareBtn);
    draggable(circleBtn);
    draggable(triangleBtn);

    this.canvas.on('object:moving', function (e) {
        var obj = e.target;
        obj.setCoords(); //Sets corner position coordinates based on current angle, width and height
        canvas.forEachObject(function (targ) {
            activeObject = canvas.getActiveObject();


            if (targ === activeObject) return;


            if (Math.abs(activeObject.oCoords.tr.x - targ.oCoords.tl.x) < edgedetection) {
                activeObject.left = targ.left - activeObject.currentWidth;

            }
            if (Math.abs(activeObject.oCoords.tl.x - targ.oCoords.tr.x) < edgedetection) {
                activeObject.left = targ.left + targ.currentWidth;

            }
            if (Math.abs(activeObject.oCoords.br.y - targ.oCoords.tr.y) < edgedetection) {
                activeObject.top = targ.top - activeObject.currentHeight;
            }
            if (Math.abs(targ.oCoords.br.y - activeObject.oCoords.tr.y) < edgedetection) {
                activeObject.top = targ.top + targ.currentHeight;
            }
            if (activeObject.intersectsWithObject(targ) && targ.intersectsWithObject(activeObject)) {

            } else {
                targ.strokeWidth = 0;
                targ.stroke = false;


            }
            if (!activeObject.intersectsWithObject(targ)) {
                activeObject.strokeWidth = 0;
                activeObject.stroke = false;
                activeObject === targ
            }
        });
    });
}

More codes that I found but doesn't answer my problem:

var canvas = new fabric.Canvas('c');

canvas.on("after:render", function(){canvas.calcOffset();});

var started = false;
var x = 0;
var y = 0;
var width = 0;
var height = 0;

canvas.on('mouse:down', function(options) {
  //console.log(options.e.clientX, options.e.clientY);

  x = options.e.clientX;
  y = options.e.clientY;

  canvas.on('mouse:up', function(options) {

    width = options.e.clientX - x;
    height = options.e.clientY - y;   

    var square = new fabric.Rect({

        width: width, 
        height: height, 
        left: x + width/2 - canvas._offset.left, 
        top: y + height/2 - canvas._offset.top, 
        fill: 'red',
        opacity: .2
    });
    canvas.add(square);
    canvas.off('mouse:up');
    $('#list').append('<p>Test</p>');

  });

});

This code adds a rectangle to the canvas. But the problem is this doesn't achieve what I want which is basically, as previously stated, that I want to be able to drag an img element and then wherever you drag that image on the canvas it will drop it precisely at that location.

CREDITS
Fabric JS: Copy/paste object on mouse down
fabric.js Offset Solution

1条回答
可以哭但决不认输i
2楼-- · 2019-03-31 23:14

it doesn't need to do some intricate stuff.

A logical framework under which to implement image dragging might be to monitor mouse events using event listeners.

On mouse down over an Image element within the page but not over the canvas, record which image element and the mouse position within the image. On mouse up anywhere set this record back to null.

On mouse over of the canvas with a non empty image record, create a Fabric image element from the Image element (as per documentation), calculate where it goes from the recorded image position and current mouse position, paste it under the mouse, make it draggable and simulate the effect of a mouse click to continue dragging it.

I have taken this question to be about the design and feasibility stages of program development.

查看更多
登录 后发表回答