简体   繁体   中英

Fabric.js right mouse click

Is there a way to receive right click mouse events on a Fabric.js canvas?

The following code works only with left click:

canvas.observe('mouse:down', function(){console.log('mouse down'));

NOTE: Most answers above are outdated; this answer applies to the latest Fabric version 2.7.0


Simply enable firing right/middle click events for your Fabric canvas

The config for firing right click and middle click events in the canvas can be found here for fireRightClick and here for fireMiddleClick and are set to false by default. This means right and middle click events are by default disabled. The parameter stopContextMenu for stopping context menu to show up on the canvas when right clicking can be found here

You can enable these simply by setting the values when creating your canvas:

var canvas = new fabric.Canvas('canvas', {
  height: height,
  width: width,
  fireRightClick: true,  // <-- enable firing of right click events
  fireMiddleClick: true, // <-- enable firing of middle click events
  stopContextMenu: true, // <--  prevent context menu from showing
});

Now your mousedown event will fire for all clicks and you can distinguish them by using the button identifier on the event:

For canvas:

canvas.on('mouse:down', (event) => {
    if(event.button === 1) {
        console.log("left click");
    }
    if(event.button === 2) {
        console.log("middle click");
    }
    if(event.button === 3) {
        console.log("right click");
    }
}

For objects:

object.on('mousedown', (event) => {
    if(event.button === 1) {
        console.log("left click");
    }
    if(event.button === 2) {
        console.log("middle click");
    }
    if(event.button === 3) {
        console.log("right click");
    }
}

When clicking on objects you can reach the "real" mouse dom event through event.e:

if(event.button === 3){
  console.log(event.e);
}

I've implemented right click by extending the fabric.Canvas class. Take a look here the _onMouseDown method.

Basically the right mouse down event for an object was disabled in fabricjs by default.

If you want to handle right clicks (on canvas or its objects), then set context menu listener on upper-canvas element. Using canvas method findTarget you can check if any target was clicked and if so, you can check type of the target.

let scope = this;
jQuery(".upper-canvas").on('contextmenu', function (options: any) {
    let target: any = scope.canvas.findTarget(options, false);
    if (target) {
        let type: string = target.type;
        if (type === "group") {
            console.log('right click on group');
        } else {
            scope.canvas.setActiveObject(target);
            console.log('right click on target, type: ' + type);
        }
    } else {
        scope.canvas.discardActiveObject();
        scope.canvas.discardActiveGroup();
        scope.canvas.renderAll();
        console.log('right click on canvas');
    }
    options.preventDefault();
});

The way I did this was to listen for a right click event across the entire canvas and match up the x,y coordinates of the click event to the object which is currently sitting at the given location. This solution feels a little like a hack but hey, it works!

$('#my_canvas').bind('contextmenu', function (env) {
    var x = env.offsetX;
    var y = env.offsetY;
    $.each (canvas._objects, function(i, e) {
        // e.left and e.top are the middle of the object use some "math" to find the outer edges
        var d = e.width / 2;
        var h = e.height / 2;
        if (x >= (e.left - d) && x <= (e.left+d)) {
            if(y >= (e.top - h) && y <= (e.top+h)) {
                console.log("clicked canvas obj #"+i);
                //TODO show custom menu at x, y
                return false; //in case the icons are stacked only take action on one.
            }
        }
    });
    return false; //stops the event propigation
});

Here's what I did, which makes use of some built-in fabric object detection code:

$('.upper-canvas').bind('contextmenu', function (e) {
    var objectFound = false;
    var clickPoint = new fabric.Point(e.offsetX, e.offsetY);

    e.preventDefault();

    canvas.forEachObject(function (obj) {
        if (!objectFound && obj.containsPoint(clickPoint)) {
            objectFound = true;
            //TODO: whatever you want with the object
        }
    });
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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