【问题标题】:How to add context menu on Raphael element?如何在 Raphael 元素上添加上下文菜单?
【发布时间】:2013-08-02 18:25:03
【问题描述】:

我正在使用 ExtJS 4 框架,并且还在我的主应用程序面板中使用Raphael.js

首先我试图阻止常规上下文菜单显示,我发现了非常简单的解决方案。

raphael_element.node.oncontextmenu = function()
{
    return false;
} 

这很好用,但在返回 false 之前,我想添加一些代码来显示我自己的自定义菜单。
有人知道怎么做吗?

我在 html 中有一些东西,正在考虑在菜单中使用:

<ul id="rect_menu" class="contextMenu">
    <li><a href="call_to_js_function">Set aaa</a></li>
    <li><a href="call_to_js_function">Set xxx</a></li>
    <li><a href="call_to_js_function">Set ccc</a></li>
</ul>

如您所见,我有css class(代码不在此处,它无关紧要)用于样式设置,id=rect_menu 在用户右键单击时显示,即拉斐尔矩形对象。

谁能展示一个方法,也许是不涉及 jquery 的小演示? Thnaks

【问题讨论】:

    标签: javascript extjs extjs4 raphael contextmenu


    【解决方案1】:

    您可以使用 Ext 在 floating 组件中显示您的自定义 HTML:

    var menu = Ext.create('Ext.Component', {
        floating: true
        ,html: ['<ul id="rect_menu" class="contextMenu">',
            '<li><a href="call_to_js_function">Set aaa</a></li>',
            '<li><a href="call_to_js_function">Set xxx</a></li>',
            '<li><a href="call_to_js_function">Set ccc</a></li>',
            '</ul>'].join('')
    });
    
    Ext.get(raphael_element.node).on({
        contextmenu: function(e) {
            menu.showAt(e.getXY());
            e.preventDefault();
        }
    });
    

    但是,显示菜单并不是棘手的部分。隐藏菜单的逻辑,无论是当用户在菜单外部单击时,还是在按下 ESC 键时都涉及更多。这就是为什么我会使用普通的Menu 让 Ext 为我们完成繁重的工作。

    var menu = Ext.create('Ext.menu.Menu', {
        items: [{
            text: 'Set aaa'
            ,handler: function() {
                // logic for aaa
            }
        }, {
            text: 'Set bbb'
            ,handler: function() {
                // logic for bbb
            }
        }]
    });
    
    Ext.get(raphael_element.node).on({
        contextmenu: function(e) {
            menu.showAt(e.getXY());
            e.preventDefault();
        }
    });
    

    现在,如果您对使用所有菜单系统、Ext 菜单项等不感兴趣,并且您真的想呈现自己的 HTML,您仍然可以利用 Ext 菜单从其隐藏机制中受益:

    var menu = Ext.create('Ext.menu.Menu', {
        // This will prevent the icon gutter from showing, and your component from
        // being left padded
        plain: true
        ,items: [{
            xtype: 'component'
            ,html: ['<ul id="rect_menu" class="contextMenu">',
                '<li><a href="call_to_js_function">Set aaa</a></li>',
                '<li><a href="call_to_js_function">Set xxx</a></li>',
                '<li><a href="call_to_js_function">Set ccc</a></li>',
                '</ul>'].join('')
        }]
    });
    
    Ext.get(raphael_element.node).on({
        contextmenu: function(e) {
            menu.showAt(e.getXY());
            e.preventDefault();
        }
    });
    

    这是使用最后一个示例的fiddle。它不使用 Raphael,但从你得到一个不具有任何重要性的 DOM 元素的那一刻起。

    编辑带有实际拉斐尔元素的示例

    我已经用实际的 Raphael 元素更新了 my fiddle。它确实按预期工作。

    很酷的是元素的点击事件完全尊重矢量路径边界,这意味着您可以精确地决定菜单将在哪里弹出或不弹出。不那么酷的是,例如,著名的tiger,这意味着 240 个事件处理程序......在性能方面有点糟糕......你总是可以将处理程序添加到 SVG 元素而不是单个形状元素, 但是菜单将绑定到整个绘图矩形而不是单个部分。

    // --- Creating a ball (see http://raphaeljs.com/ball.html)
    Raphael.fn.ball = function (x, y, r, hue) {
        hue = hue || 0;
        return this.set(
            this.ellipse(x, y + r - r / 5, r, r / 2).attr({fill: "rhsb(" + hue + ", 1, .25)-hsb(" + hue + ", 1, .25)", stroke: "none", opacity: 0}),
            this.ellipse(x, y, r, r).attr({fill: "r(.5,.9)hsb(" + hue + ", 1, .75)-hsb(" + hue + ", .5, .25)", stroke: "none"}),
            this.ellipse(x, y, r - r / 5, r - r / 20).attr({stroke: "none", fill: "r(.5,.1)#ccc-#ccc", opacity: 0})
        );
    };
    
    var R = Raphael("holder"), x = 310, y = 180, r = 150;
    var ball = R.ball(x, y, r, Math.random());
    
    // --- Creatin a custom menu
    var menu = Ext.create('Ext.menu.Menu', {
        plain: true
        ,cls: 'myContextMenu'
        ,items: [{
            xtype: 'component'
            ,html: ['<ul id="rect_menu" class="contextMenu">',
                '<li><a href="call_to_js_function">Set aaa</a></li>',
                '<li><a href="call_to_js_function">Set xxx</a></li>',
                '<li><a href="call_to_js_function">Set ccc</a></li>',
                '</ul>'].join('')
        }]
    });
    
    // --- Adding menu handler to all ball's elements
    
    var contextMenuHandler = function(e) {
        menu.showAt(e.getXY());
        e.preventDefault();
    };
    
    Ext.each(ball, function(raphaelElement) {
        Ext.fly(raphaelElement.node).on({
            contextmenu: contextMenuHandler
        });
    });
    

    【讨论】:

    • 所以同样的事情应该适用于 raphael 对象?它会阻止常规菜单不出现吗?
    • 您可以将常规 DOM 元素传递给 Ext.get,并且您可以使用 Element.node 获取 Raphael 元素的 DOM(就像您在自己的代码中所做的那样)。所以是的,这应该与 Raphael 对象完全相同。阻止默认浏览器菜单出现的是preventDefault 调用。
    • 出于好奇,我用实际的拉斐尔元素进行了测试。查看我更新的答案和小提琴。
    • 对了,你知道如何让菜单在选择后消失吗?
    • 嗯,你可能有一些处理你的菜单项?只需从那里拨打menu.hide()
    【解决方案2】:

    这也很好用,并且在 MIT 许可下

    https://swisnl.github.io/jQuery-contextMenu//

    JsFiddle (example copied from link above)

    $(function() {
        $.contextMenu({
            selector: '.context-menu-one', 
            callback: function(key, options) {
                var m = "clicked: " + key;
                window.console && console.log(m) || alert(m); 
            },
            items: {
                "edit": {name: "Edit", icon: "edit"},
                "cut": {name: "Cut", icon: "cut"},
               copy: {name: "Copy", icon: "copy"},
                "paste": {name: "Paste", icon: "paste"},
                "delete": {name: "Delete", icon: "delete"},
                "sep1": "---------",
                "quit": {name: "Quit", icon: function(){
                    return 'context-menu-icon context-menu-icon-quit';
                }}
            }
        });
    
        $('.context-menu-one').on('click', function(e){
            console.log('clicked', this);
        })    
    });
    

    【讨论】:

      猜你喜欢
      • 2022-11-28
      • 2016-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-19
      • 2013-12-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多