如何在Raphael元素上添加上下文菜单?

时间:2013-08-02 18:25:04

标签: javascript extjs extjs4 raphael contextmenu

我正在使用 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显示用户右键单击即。 Raphael矩形对象。

任何人都可以展示一种方式,也许是不涉及jquery的小型演示? Thnaks

2 个答案:

答案 0 :(得分:3)

您可以使用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菜单从其隐藏机制中受益:< / p>

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元素

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

很酷的是,元素的click事件完全尊重矢量路径边界,这意味着您可以精确地决定菜单的弹出位置。不那么酷的是,例如,着名的tiger,这将意味着240个事件处理程序...有点performance性能明智....你总是可以将处理程序添加到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
    });
});

答案 1 :(得分:0)

这也很好,并且已获得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);
    })    
});