gpt4 book ai didi

javascript - 向节点添加上下文菜单

转载 作者:行者123 更新时间:2023-11-29 20:51:49 25 4
gpt4 key购买 nike

我正在尝试向 this jsfiddle 中的静态节点添加上下文菜单如 jakosz's example 中所示.

在右键单击节点时,它确实显示了菜单,但在屏幕的左上角,我无法弄清楚如何传递节点坐标,因此上下文菜单出现在节点周围而不是某处否则。

在帖子中复制相同的 jsfiddle。

.node {
fill: #000;
}

.cursor {
fill: green;
stroke: brown;
pointer-events: none;
}


.node text {
pointer-events: none;
font: 10px sans-serif;
}

path.link {
fill: none;
stroke: #666;
stroke-width: 1.5px;
}



.link {
fill: none;
stroke: #666;
stroke-width: 1.5px;
}

circle {
fill: green;
stroke: red;
stroke-width: 1.5px;
}

text {
font: 10px sans-serif;
pointer-events: none;
text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff;
}
    <script src="https://d3js.org/d3.v3.min.js"></script>
<script>
var width = 960, height = 500;
var links = [{source:"simulator",target:"monitor" ,type:"resolved"} , {source:"web",target:"monitor" ,type:"resolved"} ];



var nodes = [ {"id":"monitor", "grp":"system"}, {"id":"simulator", "grp":"system"}, {id:"web", grp:"client"}];


function reset() {
}


function contextMenu() {
var height,
width,
margin = 0.1, // fraction of width
items = [],
rescale = false,
style = {
'rect': {
'mouseout': {
'fill': 'rgb(244,244,244)',
'stroke': 'white',
'stroke-width': '1px'
},
'mouseover': {
'fill': 'rgb(200,200,200)'
}
},
'text': {
'fill': 'steelblue',
'font-size': '13'
}
};

function menu(x, y) {
d3.select('.context-menu').remove();
scaleItems();

// Draw the menu
d3.select('svg')
.append('g').attr('class', 'context-menu')
.selectAll('tmp')
.data(items).enter()
.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.selectAll('.menu-entry')
.append('rect')
.attr('x', x)
.attr('y', function(d, i){ return y + (i * height); })
.attr('width', width)
.attr('height', height)
.style(style.rect.mouseout);

d3.selectAll('.menu-entry')
.append('text')
.text(function(d){ return d; })
.attr('x', x)
.attr('y', function(d, i){ return y + (i * height); })
.attr('dy', height - margin / 2)
.attr('dx', margin)
.style(style.text);

// Other interactions
d3.select('body')
.on('click', function() {
d3.select('.context-menu').remove();
});

}

menu.items = function(e) {
if (!arguments.length) return items;
for (i in arguments) items.push(arguments[i]);
rescale = true;
return menu;
}

// Automatically set width, height, and margin;
function scaleItems() {
if (rescale) {
d3.select('svg').selectAll('tmp')
.data(items).enter()
.append('text')
.text(function(d){ return d; })
.style(style.text)
.attr('x', -1000)
.attr('y', -1000)
.attr('class', 'tmp');
var z = d3.selectAll('.tmp')[0]
.map(function(x){ return x.getBBox(); });
width = d3.max(z.map(function(x){ return x.width; }));
margin = margin * width;
width = width + 2 * margin;
height = d3.max(z.map(function(x){ return x.height + margin / 2; }));

// cleanup
d3.selectAll('.tmp').remove();
rescale = false;
}
}

return menu;
}


var width = 900,
height = 600,
radius = 8;


var map = {}
nodes.forEach(function(d,i){
map[d.id] = i;
})

links.forEach(function(d) {
d.source = map[d.source];
d.target = map[d.target];
})

var force = d3.layout.force()
.nodes(d3.values(nodes))
.links(links)
.size([width, height])
.linkDistance(50)
.charge(-200)
.on("tick", tick)
.start();

var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);


// Per-type markers, as they don't inherit styles.
svg.append("defs").selectAll("marker")
.data(["suit", "licensing", "resolved"])
.enter().append("marker")
.attr("id", function(d) { return d; })
.attr("viewBox", "0 -5 10 10")
.attr("refX", 15)
.attr("refY", -1.5)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("path")
.attr("d", "M0,-5L10,0L0,5");

var path = svg.append("g").selectAll("path")
.data(force.links())
.enter().append("path")
.attr("class", function(d) { return "link " + d.type; })
.attr("marker-end", function(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("circle")
.attr("r", 6)
.call(force.drag)
.on('contextmenu', function(){
d3.event.preventDefault();
menu(d3.mouse(this)[0], d3.mouse(this)[1]);
});

var text = svg.append("g").selectAll("text")
.data(force.nodes())
.enter().append("text")
.attr("x", 8)
.attr("y", ".31em")
.text(function(d) { return d.id; });

var node = svg.selectAll(".node"),
link = svg.selectAll(".link");


function mousedownNode(d, i) {
nodes.splice(i, 1);
links = links.filter(function(l) {
return l.source !== d && l.target !== d;
});
d3.event.stopPropagation();

refresh();
}

// Use elliptical arc path segments to doubly-encode directionality.
function tick() {
path.attr("d", linkArc);
circle.attr("transform", transform);
text.attr("transform", transform);
}

function linkArc(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
}

function transform(d) {
return "translate(" + d.x + "," + d.y + ")";
}



</script>

最佳答案

您想获取父组的位置,而不是圆圈的位置:

menu(d3.mouse(this.parentNode)[0], d3.mouse(this.parentNode)[1]);

或者,最惯用的方式,只使用 SVG 作为容器:

menu(d3.mouse(svg.node())[0], d3.mouse(svg.node())[1]);

这是您的代码,仅进行了更改:

.node {
fill: #000;
}

.cursor {
fill: green;
stroke: brown;
pointer-events: none;
}


.node text {
pointer-events: none;
font: 10px sans-serif;
}

path.link {
fill: none;
stroke: #666;
stroke-width: 1.5px;
}



.link {
fill: none;
stroke: #666;
stroke-width: 1.5px;
}

circle {
fill: green;
stroke: red;
stroke-width: 1.5px;
}

text {
font: 10px sans-serif;
pointer-events: none;
text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff;
}
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>
var width = 960, height = 500;
var links = [{source:"simulator",target:"monitor" ,type:"resolved"} , {source:"web",target:"monitor" ,type:"resolved"} ];



var nodes = [ {"id":"monitor", "grp":"system"}, {"id":"simulator", "grp":"system"}, {id:"web", grp:"client"}];


function reset() {
}


function contextMenu() {
var height,
width,
margin = 0.1, // fraction of width
items = [],
rescale = false,
style = {
'rect': {
'mouseout': {
'fill': 'rgb(244,244,244)',
'stroke': 'white',
'stroke-width': '1px'
},
'mouseover': {
'fill': 'rgb(200,200,200)'
}
},
'text': {
'fill': 'steelblue',
'font-size': '13'
}
};

function menu(x, y) {
d3.select('.context-menu').remove();
scaleItems();

// Draw the menu
d3.select('svg')
.append('g').attr('class', 'context-menu')
.selectAll('tmp')
.data(items).enter()
.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.selectAll('.menu-entry')
.append('rect')
.attr('x', x)
.attr('y', function(d, i){ return y + (i * height); })
.attr('width', width)
.attr('height', height)
.style(style.rect.mouseout);

d3.selectAll('.menu-entry')
.append('text')
.text(function(d){ return d; })
.attr('x', x)
.attr('y', function(d, i){ return y + (i * height); })
.attr('dy', height - margin / 2)
.attr('dx', margin)
.style(style.text);

// Other interactions
d3.select('body')
.on('click', function() {
d3.select('.context-menu').remove();
});

}

menu.items = function(e) {
if (!arguments.length) return items;
for (i in arguments) items.push(arguments[i]);
rescale = true;
return menu;
}

// Automatically set width, height, and margin;
function scaleItems() {
if (rescale) {
d3.select('svg').selectAll('tmp')
.data(items).enter()
.append('text')
.text(function(d){ return d; })
.style(style.text)
.attr('x', -1000)
.attr('y', -1000)
.attr('class', 'tmp');
var z = d3.selectAll('.tmp')[0]
.map(function(x){ return x.getBBox(); });
width = d3.max(z.map(function(x){ return x.width; }));
margin = margin * width;
width = width + 2 * margin;
height = d3.max(z.map(function(x){ return x.height + margin / 2; }));

// cleanup
d3.selectAll('.tmp').remove();
rescale = false;
}
}

return menu;
}


var width = 900,
height = 600,
radius = 8;


var map = {}
nodes.forEach(function(d,i){
map[d.id] = i;
})

links.forEach(function(d) {
d.source = map[d.source];
d.target = map[d.target];
})

var force = d3.layout.force()
.nodes(d3.values(nodes))
.links(links)
.size([width, height])
.linkDistance(50)
.charge(-200)
.on("tick", tick)
.start();

var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);


// Per-type markers, as they don't inherit styles.
svg.append("defs").selectAll("marker")
.data(["suit", "licensing", "resolved"])
.enter().append("marker")
.attr("id", function(d) { return d; })
.attr("viewBox", "0 -5 10 10")
.attr("refX", 15)
.attr("refY", -1.5)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("path")
.attr("d", "M0,-5L10,0L0,5");

var path = svg.append("g").selectAll("path")
.data(force.links())
.enter().append("path")
.attr("class", function(d) { return "link " + d.type; })
.attr("marker-end", function(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("circle")
.attr("r", 6)
.call(force.drag)
.on('contextmenu', function(){
d3.event.preventDefault();
menu(d3.mouse(svg.node())[0], d3.mouse(svg.node())[1]);
});

var text = svg.append("g").selectAll("text")
.data(force.nodes())
.enter().append("text")
.attr("x", 8)
.attr("y", ".31em")
.text(function(d) { return d.id; });

var node = svg.selectAll(".node"),
link = svg.selectAll(".link");


function mousedownNode(d, i) {
nodes.splice(i, 1);
links = links.filter(function(l) {
return l.source !== d && l.target !== d;
});
d3.event.stopPropagation();

refresh();
}

// Use elliptical arc path segments to doubly-encode directionality.
function tick() {
path.attr("d", linkArc);
circle.attr("transform", transform);
text.attr("transform", transform);
}

function linkArc(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
}

function transform(d) {
return "translate(" + d.x + "," + d.y + ")";
}



</script>

关于javascript - 向节点添加上下文菜单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51464472/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com