【问题标题】:Fabric.js right mouse clickFabric.js 鼠标右键
【发布时间】:2012-10-17 23:33:09
【问题描述】:

有没有办法在 Fabric.js 画布上接收右键单击鼠标事件?

以下代码仅适用于左键:

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

【问题讨论】:

  • 只注意画布上的点击事件(不是通过结构,而是使用 DOM 方法),然后检查它是右键单击而不是左键。
  • 对于最新版本(在 Fabric 2.7.0 中测试),您只需在画布配置中启用这些事件。见my answer below

标签: javascript canvas fabricjs


【解决方案1】:

注意: 上面的大多数答案都已过时;此答案适用于最新的 Fabric 版本 2.7.0


只需为您的 Fabric 画布启用触发右键/中间点击事件

可以在here for fireRightClickhere for fireMiddleClick 找到在画布中触发右键单击和中间单击事件的配置,默认设置为false。这意味着默认情况下禁用右键和中键单击事​​件。 右键单击时停止上下文菜单显示在画布上的参数stopContextMenu可以找到here

您只需在创建画布时设置值即可启用这些功能:

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

现在您的mousedown 事件将为所有点击触发,您可以使用事件上的按钮标识符来区分它们:

对于画布:

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

对于对象:

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

当点击对象时,你可以通过 event.e 到达“真正的”鼠标 dom 事件:

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

【讨论】:

  • 阻止上下文菜单对我不起作用。我错过了什么? IE 和 Chrome 都在画布上右键单击显示上下文菜单(控制台日志工作正常)。
  • @ps0604 您确定要在 DOM 事件 (event.e) 上调用 preventDefault()。您可以通过将其记录到控制台来仔细检查哪个对象是 DOM 事件。
  • preventDefault 对我也不起作用。使用 event.e.preventDefault 会给出“无法读取未定义的属性 'preventDefault'”。将“元素”打印到日志表明它是一个 MouseEvent。打印“element.e”显示未定义。所以我将您的代码更改为 event.preventDefault();但仍然会出现弹出窗口。我错过了什么?
  • 如果您在控制台中收到该错误消息并输出,则表示事件变量是 DOM 事件。如果你同时添加event.preventDefault(); event.stopPropagation(); 会发生什么我会尝试一次。你用的是什么版本的 canvas.js?
  • 这是一个显示结果的小提琴。我还必须重新编号按钮才能正确。我一直在使用 2.4.6,但是当我看到这篇文章时切换到 2.7.0。两者都导致相同的操作:jsfiddle.net/morrowsend/qzr1s2a7/5
【解决方案2】:

我通过扩展 fabric.Canvas 类实现了右键单击。看看here_onMouseDown方法。

基本上,fabricjs 中默认禁用了对象的鼠标右键事件。

【讨论】:

  • 嗨,没关系,但我还是不明白。如果我在你的库中使用这个扩展的 _onMouseDown 事件,右键单击会发生什么。在问题的上下文中想要的行为是 - 如果我们有一个上下文菜单插件,我们想要覆盖 this.canvas.on('mouse:down', (e) => someFunc(e)); 上的默认行为。并从插件触发功能以显示上下文菜单。同时右键单击默认浏览器上下文菜单不应该存在。这应该是插件本身的责任,但只是想知道我们是否应该使用 fabricJs 做其他事情
  • 我个人使用 angular 6 并且 $('#my_canvas').bind('contextmenu') 对我不起作用。我更喜欢以打字稿方式(OOP方式)“干净地”扩展事件和对象。
【解决方案3】:

如果您想处理右键单击(在画布或其对象上),则在画布上部元素上设置上下文菜单侦听器。使用 canvas 方法 findTarget 你可以检查是否有任何目标被点击,如果是,你可以检查目标的类型。

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

【讨论】:

  • 您的回答当然值得稍微解释一下。请参考stackoverflow.com/help/how-to-answer
  • 太棒了,稍微修改一下,去掉discardActiveGroup,去掉“group”和“aciveSelection”的类型区别。
【解决方案4】:

我这样做的方法是在整个画布上侦听右键单击事件,并将单击事件的 x、y 坐标与当前位于给定位置的对象匹配。这个解决方案感觉有点像 hack,但嘿,它有效!

$('#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
});

【讨论】:

  • @jsbeckr 它的工作原理是它找到与这些坐标匹配的第一个画布对象然后停止。你可以变得更聪明,在那个 x/y 位置建立一个对象列表,然后选择其中一个来采取行动(例如,z-index 最高的那个?)
  • 是的,我做到了。而且我意识到您的解决方案不考虑缩放对象。这很令人沮丧...... :D 但很容易解决这个问题:var d = e.width * e.scaleX / 2;var h = e.height * e.scaleY / 2;
  • @jsbeckr 旋转对象呢?你也设法解决这个问题吗?
  • @Bor691 抱歉,我不需要那个。 ://
【解决方案5】:

这是我所做的,它利用了一些内置的织物对象检测代码:

$('.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
        }
    });
});

【讨论】:

  • 嗨!出于某种原因,在画布上单击返回时,菜单不会消失。有什么想法吗?
猜你喜欢
  • 2014-01-26
  • 2014-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多