Javascript 向节点添加上下文菜单

Javascript 向节点添加上下文菜单,javascript,d3.js,Javascript,D3.js,我正在尝试向中的静态节点添加上下文菜单,如中所示 在右键单击节点时,确实会显示菜单,但在屏幕的左上方,我无法确定如何传递节点坐标,因此上下文菜单显示在节点周围,而不是其他地方 在文章中复制相同的JSFIDLE .node{ 填写:#000; } .光标{ 填充:绿色; 笔画:棕色; 指针事件:无; } .节点文本{ 指针事件:无; 字体:10px无衬线; } 路径链接{ 填充:无; 行程:#666; 笔划宽度:1.5px; } .链接{ 填充:无; 行程:#666; 笔划宽度:1.5px; }

我正在尝试向中的静态节点添加上下文菜单,如中所示

在右键单击节点时,确实会显示菜单,但在屏幕的左上方,我无法确定如何传递节点坐标,因此上下文菜单显示在节点周围,而不是其他地方

在文章中复制相同的JSFIDLE

.node{
填写:#000;
}
.光标{
填充:绿色;
笔画:棕色;
指针事件:无;
}
.节点文本{
指针事件:无;
字体:10px无衬线;
}
路径链接{
填充:无;
行程:#666;
笔划宽度:1.5px;
}
.链接{
填充:无;
行程:#666;
笔划宽度:1.5px;
}
圈{
填充:绿色;
笔画:红色;
笔划宽度:1.5px;
}
正文{
字体:10px无衬线;
指针事件:无;
文本阴影:01px0#fff,1px0#fff,0-1px0#fff,-1px0#fff;
}

变量宽度=960,高度=500;
var links=[{source:“模拟器”,target:“监视器”,type:“已解析”},{source:“web”,target:“监视器”,type:“已解析”}];
var节点=[{“id”:“monitor”,“grp”:“system”},{“id”:“simulator”,“grp”:“system”},{id:“web”,grp:“client”}];
函数重置(){
}
函数上下文菜单(){
变量高度,
宽度,
边距=0.1,//宽度的分数
项目=[],
重缩放=假,
样式={
“rect”:{
“老鼠出没”:{
“填充”:“rgb(244244244)”,
“笔划”:“白色”,
“笔划宽度”:“1px”
}, 
“鼠标悬停”:{
'填充':'rgb(200200)'
}
}, 
“文本”:{
“填充”:“钢蓝”,
“字体大小”:“13”
}
}; 
功能菜单(x,y){
d3.选择('.context menu').remove();
scaleItems();
//画菜单
d3.选择(“svg”)
.append('g').attr('class','context menu'))
.selectAll('tmp')
.数据(项)。输入()
.append('g').attr('class','menu entry'))
.style({'cursor':'pointer'})
.on('mouseover',function(){
d3.select(this.select('rect').style(style.rect.mouseover)})
.on('mouseout',function(){
d3.select(this.select('rect').style(style.rect.mouseout)});
d3.选择全部(“.菜单项”)
.append('rect')
.attr('x',x)
.attr('y',函数(d,i){返回y+(i*高度);})
.attr('width',width)
.attr('height',height)
.style(style.rect.mouseout);
d3.选择全部(“.菜单项”)
.append('文本')
.text(函数(d){return d;})
.attr('x',x)
.attr('y',函数(d,i){返回y+(i*高度);})
.attr('dy',高度-余量/2)
.attr('dx',边距)
.style(style.text);
//其他互动
d3.选择('主体')
.on('单击',函数()){
d3.选择('.context menu').remove();
});
}
菜单项=功能(e){
如果(!arguments.length)返回项;
对于(参数中的i)项,push(参数[i]);
重新缩放=真;
返回菜单;
}
//自动设置宽度、高度和边距;
函数scaleItems(){
如果(重新缩放){
d3.选择('svg')。选择全部('tmp'))
.数据(项)。输入()
.append('文本')
.text(函数(d){return d;})
.style(style.text)
.attr('x',-1000)
.attr('y',-1000)
.attr('class','tmp');
var z=d3.selectAll('.tmp')[0]
.map(函数(x){return x.getBBox();});
width=d3.max(z.map(函数(x){return x.width;}));
边距=边距*宽度;
宽度=宽度+2*边距;
height=d3.max(z.map(函数(x){return x.height+margin/2;}));
//清理
d3.选择所有('.tmp').remove();
重缩放=假;
}
}
返回菜单;
}
可变宽度=900,
高度=600,
半径=8;
变量映射={}
forEach(函数(d,i){
map[d.id]=i;
})
links.forEach(函数(d){
d、 source=map[d.source];
d、 target=map[d.target];
})
var-force=d3.layout.force()
.节点(d3.值(节点))
.链接(links)
.尺寸([宽度、高度])
.linkDistance(50)
。收费(-200)
.on(“滴答”,滴答)
.start();
var svg=d3.选择(“正文”).追加(“svg”)
.attr(“宽度”,宽度)
.attr(“高度”,高度);
//每类型标记,因为它们不继承样式。
svg.append(“defs”).selectAll(“marker”)
.数据([“诉讼”、“许可”、“已解决”])
.enter().append(“标记”)
.attr(“id”,函数(d){return d;})
.attr(“视图框”,“0-5 10”)
.attr(“参考文献”,第15页)
.attr(“参考文献”,-1.5)
.attr(“markerWidth”,6)
.attr(“markerHeight”,6)
.attr(“方向”、“自动”)
.append(“路径”)
.attr(“d”,“M0,-5L10,0L0,5”);
var path=svg.append(“g”).selectAll(“path”)
.data(force.links())
.enter().append(“路径”)
.attr(“类”,函数(d){return“link”+d.type;})
.attr(“marker end”,函数(d){return”url(#“+d.type+”);});
var menu=contextMenu().items('first item','second option','whatever,man');
var circle=svg.append(“g”).selectAll(“circle”)
.data(force.nodes())
.enter().append(“圆”)
.attr(“r”,6)
.call(强制拖动)
.on('contextmenu',函数(){
d3.event.preventDefault();
菜单(d3.鼠标(此)[0],d3.鼠标(此)[1]);
});
var text=svg.append(“g”).selectAll(“text”)
.data(force.nodes())
.enter().append(“文本”)
.attr(“x”,8)
.attr(“y”,“.31em”)
.text(函数(d){返回d.id;});
var node=svg.selectAll(“.node”),
link=svg.selectAll(“.link”);
函数mo
menu(d3.mouse(this.parentNode)[0], d3.mouse(this.parentNode)[1]);
menu(d3.mouse(svg.node())[0], d3.mouse(svg.node())[1]);