D3 oncontext menu , change node color selected - javascript

I have nodes (that are rectangles) with a right click menu, I am trying to change the color on the node depending on the outcome of the onclick menu but the nodes don't change colors. I have different ways/attempts in the code to see what I may be doing wrong. There are alot of forums with onclick doubleclick, but not with oncontextmenu. Any help would be great and thanks
var node = svg.selectAll("g.node")
.data(json.nodes)
.enter().append("g")
.attr("r", 12)
.attr("class", "node")
.attr("class", "gLink")
.call(node_drag)
.on('contextmenu', function(d,i) {
d3.selectAll('.context-menu').data([1])
.enter()
.append('div')
.attr('class', 'context-menu');
// close menu
d3.select('body').on('click.context-menu', function() {
d3.select('.context-menu').style('display', 'none');
});
// this gets executed when a contextmenu event occurs
d3.selectAll('.context-menu')
.html('')
.append('ul')
.selectAll('li')
.data(actions).enter()
.append('li')
.on('click' , function(d) {
if (d=="Force Succeed"){
alert(d);
d3.select(".node").style("fill", "#000");
}
else if (d=="Start Node"){
alert(d);
d3.select(this).style("fill", "#000000");
}
else if (d=="Start Tree"){
alert(d);
d3.select(this).style("fill", "#000");
}
else {
alert(d);
d3.select(this).style("fill", "#000");
}
})
.text(function(d) { return d; });
d3.select('.context-menu').style('display', 'none');
// show the context menu
d3.select('.context-menu')
.style('left', (d3.event.pageX - 2) + 'px')
.style('top', (d3.event.pageY - 2) + 'px')
.style('display', 'block');
d3.event.preventDefault();
});
node.append("svg:rect")
.attr("x", function(d) { return -1 * (d.name.length * 10) / 2 })
.attr("y", -15)
.attr("rx", 5)
.attr("ry", 5)
.attr("width", function(d) { return d.name.length * 10; })
.attr("height", 20)
.style("fill", "#FFF")
.style("stroke", "#6666FF");

Just keep a reference to the object that was right-clicked for the context menu:
.on('contextmenu', function(d, i) {
var self = d3.select(this); //<-- keep this reference
d3.selectAll('.context-menu').data([1])
.enter()
...
.on('click', function(d) {
if (d == "Force Succeed") {
self.style("fill", "green"); //<-- use it later
...
Here's a functional example, extrapolated from your code snippet:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
</head>
<body>
<script>
var svg = d3.select('body')
.append('svg')
.attr('width', 500)
.attr('height', 500);
var json = {};
json.nodes = [
0, 1, 2, 3
];
var actions = ["Force Succeed", "Start Node", "Start Tree"];
var node = svg.selectAll("g.node")
.data(json.nodes)
.enter().append("circle")
.attr("r", 12)
.attr("cx", function(d){
return d * 30 + 15;
})
.attr("cy", 15)
.on('contextmenu', function(d, i) {
var self = d3.select(this);
d3.selectAll('.context-menu').data([1])
.enter()
.append('div')
.attr('class', 'context-menu');
// close menu
d3.select('body').on('click.context-menu', function() {
d3.select('.context-menu').style('display', 'none');
});
// this gets executed when a contextmenu event occurs
d3.selectAll('.context-menu')
.html('')
.append('ul')
.selectAll('li')
.data(actions).enter()
.append('li')
.on('click', function(d) {
if (d == "Force Succeed") {
self.style("fill", "green");
} else if (d == "Start Node") {
self.style("fill", "red");
} else if (d == "Start Tree") {
self.style("fill", "blue");
} else {
self.style("fill", "#000");
}
})
.text(function(d) {
return d;
});
d3.select('.context-menu').style('display', 'none');
// show the context menu
d3.select('.context-menu')
.style('left', (d3.event.pageX - 2) + 'px')
.style('top', (d3.event.pageY - 2) + 'px')
.style('display', 'block')
.style('position', 'absolute');
d3.event.preventDefault();
});
node.append("svg:rect")
.attr("x", function(d) {
return -1 * (3 * 10) / 2
})
.attr("y", -15)
.attr("rx", 5)
.attr("ry", 5)
.attr("width", function(d) {
return 3 * 10;
})
.attr("height", 20)
.style("fill", "#FFF")
.style("stroke", "#6666FF");
</script>
</body>
</html>

Related

D3 incorrect drag behaviour

This is a follow on from my previous question
d3 rect in one group interfering with rect in another group
Two issues:
Incorrect drag behaviour. When clicking on the second rect to drag it, it jumps to where the third one is.
I added a anonymous function which runs when the svg in clicked on anywhere. This should add a new rect. However that is the working.
I know I should have only one issue per question but these are related and I suspect they will be solved together.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
/*.active {
stroke: #000;
stroke-width: 2px;
}*/
</style>
<svg width="960" height="500"></svg>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
var margin = {
top: 20,
right: 20,
bottom: 20,
left: 20
},
width = 600 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
var svg = d3.select("svg");
var data = [{
x: 200
}, {
x: 300
}, {
x: 400
}];
var groove = svg.append("g")
.attr("class", "groove_group");
groove.append("rect")
.attr("x", 100)
.attr("y", 150)
.attr("rx", 2)
.attr("ry", 2)
.attr("height", 6)
.attr("width", 800)
.style("fill", "grey");
groove.append("rect")
.attr("x", 102)
.attr("y", 152)
.attr("rx", 2)
.attr("ry", 2)
.attr("height", 2)
.attr("width", 796)
.style("fill", "black");
// create group
var group = svg.selectAll(null)
.data(data)
.enter().append("g")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.on("click", removeElement);
group.append("rect")
.attr("x", function(d) {
return d.x;
})
.attr("y", 100)
.attr("height", 100)
.attr("width", 15)
.style("fill", "lightblue")
.attr('id', function(d, i) {
return 'handle_' + i;
})
.attr("rx", 6)
.attr("ry", 6)
.attr("stroke-width", 2)
.attr("stroke", "black");
group.append("text")
.attr("x", function(d) {
return d.x
})
.attr("y", 100)
.attr("text-anchor", "start")
.style("fill", "black")
.text(function(d) {
return "x:" + d.x
});
// create group
var group = svg.selectAll("g")
.data(data)
.enter().append("g")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.on("click", removeElement);
group.append("rect")
.attr("x", function(d) {
return d.x;
})
.attr("y", 200)
.attr("height", 100)
.attr("width", 15)
.style("fill", "lightblue")
.attr('id', function(d, i) {
return 'handle_' + i;
})
.attr("rx", 6)
.attr("ry", 6)
.attr("stroke-width", 2)
.attr("stroke", "black");
group.append("text")
.attr("x", function(d) {
return d.x
})
.attr("y", 200)
.attr("text-anchor", "start")
.style("fill", "black")
.text(function(d) {
return "x:" + d.x
});
svg.on("click", function() {
var coords = d3.mouse(this);
var newData = {
x: d3.event.x,
}
data.push(newData);
group.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", function(d) {
return d.x;
})
.attr("y", 200)
.attr("height", 100)
.attr("width", 15)
.style("fill", "steelblue")
.attr('id', function(d, i) {
return 'rect_' + i;
})
.attr("rx", 6)
.attr("ry", 6)
.attr("stroke-width", 2)
.attr("stroke", "black");
});
function dragstarted(d) {
d3.select(this).raise().classed("active", true);
}
function dragged(d) {
d3.select(this).select("text")
.attr("x", d.x = d3.event.x);
d3.select(this).select("rect")
.attr("x", d.x = d3.event.x);
}
function dragended(d) {
d3.select(this)
.classed("active", false);
}
function removeElement(d) {
d3.event.stopPropagation();
data = data.filter(function(e) {
return e != d;
});
d3.select(this)
.remove();
}
</script>
Here are the explanations to your issues:
You are reassigning var groups, that is, you have two var groups in your code, the last one overwriting the first one. Just remove the last variable.
In your function to append new rectangles, you are using an update selection that selects rectangles. However, your enter selection appends groups (<g>) elements, not rectangles.
Have a look at the refactored function, it binds the data to a newly created group and appends the rectangle to that group:
var newGroup = svg.selectAll(".group")
.data(data, function(d) {
return d.x
})
.enter()
.append("g")
//etc...
newGroup.append("rect")
//etc...
Also, use a key selection in the data binding, so you know exactly what rectangle is being dragged:
.data(data, function(d){return d.x})
Here is your code with those changes:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
/*.active {
stroke: #000;
stroke-width: 2px;
}*/
</style>
<svg width="960" height="500"></svg>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
var margin = {
top: 20,
right: 20,
bottom: 20,
left: 20
},
width = 600 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
var svg = d3.select("svg");
var data = [{
x: 200
}, {
x: 300
}, {
x: 400
}];
var groove = svg.append("g")
.attr("class", "groove_group");
groove.append("rect")
.attr("x", 100)
.attr("y", 150)
.attr("rx", 2)
.attr("ry", 2)
.attr("height", 6)
.attr("width", 800)
.style("fill", "grey");
groove.append("rect")
.attr("x", 102)
.attr("y", 152)
.attr("rx", 2)
.attr("ry", 2)
.attr("height", 2)
.attr("width", 796)
.style("fill", "black");
// create group
var group = svg.selectAll(null)
.data(data, function(d){return d.x})
.enter().append("g")
.attr("class", "group")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.on("click", removeElement);
group.append("rect")
.attr("x", function(d) {
return d.x;
})
.attr("y", 100)
.attr("height", 100)
.attr("width", 15)
.style("fill", "lightblue")
.attr('id', function(d, i) {
return 'handle_' + i;
})
.attr("rx", 6)
.attr("ry", 6)
.attr("stroke-width", 2)
.attr("stroke", "black");
group.append("text")
.attr("x", function(d) {
return d.x
})
.attr("y", 100)
.attr("text-anchor", "start")
.style("fill", "black")
.text(function(d) {
return "x:" + d.x
});
svg.on("click", function() {
var coords = d3.mouse(this);
var newData = {
x: coords[0],
}
data.push(newData);
var newGroup = svg.selectAll(".group")
.data(data, function(d){return d.x})
.enter()
.append("g")
.attr("class", "group")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.on("click", removeElement);
newGroup.append("rect")
.attr("x", function(d) {
return d.x;
})
.attr("y", 200)
.attr("height", 100)
.attr("width", 15)
.style("fill", "steelblue")
.attr('id', function(d, i) {
return 'rect_' + i;
})
.attr("rx", 6)
.attr("ry", 6)
.attr("stroke-width", 2)
.attr("stroke", "black");
});
function dragstarted(d) {
d3.select(this).raise().classed("active", true);
}
function dragged(d) {
d3.select(this).select("text")
.attr("x", d.x = d3.event.x);
d3.select(this).select("rect")
.attr("x", d.x = d3.event.x);
}
function dragended(d) {
d3.select(this)
.classed("active", false);
}
function removeElement(d) {
d3.event.stopPropagation();
data = data.filter(function(e) {
return e != d;
});
d3.select(this)
.remove();
}
</script>
For correctly drag-and-drop behavior, rewrite your code like this:
var margin = {
top: 20,
right: 20,
bottom: 20,
left: 20
},
width = 600 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
var svg = d3.select("svg");
var data = [{
x: 200
}, {
x: 300
}, {
x: 400
}];
var groove = svg.append("g")
.attr("class", "groove_group");
groove.append("rect")
.attr("x", 100)
.attr("y", 150)
.attr("rx", 2)
.attr("ry", 2)
.attr("height", 6)
.attr("width", 800)
.style("fill", "grey");
groove.append("rect")
.attr("x", 102)
.attr("y", 152)
.attr("rx", 2)
.attr("ry", 2)
.attr("height", 2)
.attr("width", 796)
.style("fill", "black");
// create group
var group = svg.selectAll(null)
.data(data)
.enter().append("g")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.on("click", removeElement);
group.append("rect")
.attr("x", function(d) {
return d.x;
})
.attr("y", 100)
.attr("height", 100)
.attr("width", 15)
.style("fill", "lightblue")
.attr('id', function(d, i) {
return 'handle_' + i;
})
.attr("rx", 6)
.attr("ry", 6)
.attr("stroke-width", 2)
.attr("stroke", "black");
group.append("text")
.attr("x", function(d) {
return d.x
})
.attr("y", 100)
.attr("text-anchor", "start")
.style("fill", "black")
.text(function(d) {
return "x:" + d.x
});
svg.on("click", function() {
var coords = d3.mouse(this);
var newData = {
x: d3.event.x,
}
data.push(newData);
group.selectAll("rect")
.data(data)
.exit()
.enter()
.append("rect")
.attr("x", function(d) {
return d.x;
})
.attr("y", 200)
.attr("height", 100)
.attr("width", 15)
.style("fill", "steelblue")
.attr('id', function(d, i) {
return 'rect_' + i;
})
.attr("rx", 6)
.attr("ry", 6)
.attr("stroke-width", 2)
.attr("stroke", "black");
});
function dragstarted(d) {
d3.select(this).raise().classed("active", true);
}
function dragged(d) {
d3.select(this).select("text")
.attr("x", d.x = d3.event.x);
d3.select(this).select("rect")
.attr("x", d.x = d3.event.x);
}
function dragended(d) {
d3.select(this)
.classed("active", false);
}
function removeElement(d) {
d3.event.stopPropagation();
data = data.filter(function(e) {
return e != d;
});
d3.select(this)
.remove();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.2/d3.min.js"></script>
<svg width="960" height="500"></svg>
But, what the problem with adding the new element, I have no idea.

d3 inverse bubble and label animation

I am looking to animate this chart.
http://jsfiddle.net/NYEaX/1554/
var invisiblebubble = mask.append("circle")
.data(data);
invisiblebubble
.attr("cx", 550)
.attr("cy", 250)
.transition()
.duration(900)
.attr("r", function(d) {
return d.value;
});
I've animated the mask circle - looking to implement other animations/suggestions for the labels. If they tween like a pie chart, tween in an arc, fade in etc..
I did create a transition on the radius of the circle - kind of looked like the warner bros ending.
var invisiblebubble = mask.append("circle")
.data(data);
invisiblebubble
.attr("cx", 550)
.attr("cy", 250)
.transition()
.duration(2000)
.attr("r", 10)
.transition()
.duration(900)
.attr("r", function(d) {
return d.value;
});
How do I animate other features like the labels/pointers
I've managed to improve the inverse bubble chart with this code.
Where I have to set a fixed size for the circle first, mask it, then animate it - for the purpose of the labels.
function maskMaker(el){
var backcolor = $(el).data("color");
var backopacity = $(el).data("opacity");
var height = $(el).data("height");
var width = $(el).data("width");
var labelName = $(el).data("label-name");
var bubbleValue = $(el).data("bubble-value");
var displaceLeft = $(el).data("displace-left");
var displaceTop = $(el).data("displace-top");
var data = [{
"label": labelName,
"x": displaceLeft,
"y": displaceTop,
"value": bubbleValue
}];
console.log("MASK data", data);
// Set the main elements for the series chart
var svgroot = d3.select($(el)[0]).append("svg");
// filters go in defs element
var defs = svgroot.append("defs");
var mask = defs.append("mask")
.attr("id", "myMask");
mask.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", "100%")
.attr("height", "100%")
.style("fill", "white")
.style("opacity", backopacity);
var invisiblebubble = mask.append("circle")
.data(data);
//create a fixed bubble first
invisiblebubble
.attr("cx", "50%")
.attr("cy", "50%")
.attr("r", function(d) {
return d.value-20;
});
//now mask the fixed circle
var masker = defs.append(function() {
return mask.node().cloneNode(true)
})
.attr("id", "myMaskForPointer")
.select("rect")
.style("opacity", 0.8);
//animate this circle
invisiblebubble
.attr("cx", "50%")
.attr("cy", "50%")
.attr("r", 10)
.transition()
.duration(900)
.attr("r", function(d) {
return d.value;
});
//apply the rest of the chart elements
var svg = svgroot
.attr("class", "series")
.attr("width", "1120px")
.attr("height", "500px")
.append("g")
.attr("transform", "translate(0,0)")
var rect = svg
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", "100%")
.attr("height", "100%")
.attr("mask", "url(#myMask)")
.style("fill", backcolor);
/*
//__labels
var centrallabel = svgroot.append("g")
.attr("class", "centrallabel")
.data(data);
centrallabel
.append("text")
.attr("text-anchor", "middle")
.attr("x", 550)
.attr("y", 250 + 10)
.text(function(d) {
return "200";
})
*/
function addLabel(){
//__labels
var labels = svgroot.append("g")
.attr("class", "labels")
//__ enter
var labels = labels.selectAll("text")
.data(data);
labels.enter()
.append("text")
.attr("text-anchor", "middle")
//__ update
//labels
.attr("x", function(d) {
return d.x;
})
.attr("y", function(d) {
return d.y-10;
})
.text(function(d) {
return d.label;
})
.each(function(d) {
var bbox = this.getBBox();
d.sx = d.x - bbox.width / 2 - 2;
d.ox = d.x + bbox.width / 2 + 2;
d.sy = d.oy = d.y + 5;
d.cx = 550;
d.cy = 250;
})
.transition()
.duration(300)
labels
.transition()
.duration(300)
//__ exit
labels.exit().remove();
//__labels
}
function addPointer(){
//__pointers
var pointers = svgroot.append("g")
.attr("class", "pointers");
var dots = defs.append("marker")
.attr("id", "circ")
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("refX", 3)
.attr("refY", 3);
var pointers = pointers.selectAll("path.pointer")
.data(data);
//__ enter
pointers.enter()
.append("path")
.attr("class", "pointer")
.style("fill", "none")
.attr("marker-end", "url(#circ)")
.attr("mask", "url(#myMaskForPointer)")
//__ update
//pointers
.attr("d", function(d) {
if (d.cx > d.ox) {
return "M" + d.sx + "," + d.sy + "L" + d.ox + "," + d.oy + " " + d.cx + "," + d.cy;
} else {
return "M" + d.ox + "," + d.oy + "L" + d.sx + "," + d.sy + " " + d.cx + "," + d.cy;
}
})
.transition()
.duration(300)
pointers
.transition()
.duration(300)
//__ exit
pointers.exit().remove();
//__pointers
}
//delay for the mask
setTimeout(function(){
addLabel();
addPointer();
}, 1000);
}
Fade in could be implementing like :
centrallabel
.append("text")
.attr("text-anchor", "middle")
.attr("x", 550)
.style("opacity",0)
.attr("y", 250 + 10)
.text(function(d) {
return "200";
})
.transition()
.duration(2000)
.style("opacity", 1)
As far as other animations you could start the pointer line off screen then transition it to it's endpoint. Or start with its length at 0 and transition it to full size. Transform/Translate would probably be useful - see (https://bl.ocks.org/mbostock/1345853)

Prevent mouseout action after click on an element with D3.js

I would like to prevent the mouseout action of an element when the user click on this element. For an example see this JSFiddle (the circle disappear even if I click on the label).
Is there an easy way to achieve my objective with d3.js? Thank you!
The JSFiddle example code:
var svg = d3.select("#content")
.append("svg")
.attr("width", 600)
.attr("height", 400);
var g = svg.append("g");
var text = g.append("text")
.text("Click me")
.style("fill", "Blue")
.attr("x", 50)
.attr("y", 50)
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.on("click", click);
var circle = g.append("circle")
.style("fill", "Orange")
.attr("cx", 150)
.attr("cy", 90)
.attr("r", 15)
.classed("hide", true)
.classed("someClass", true);
function mouseover(p){
d3.selectAll("circle.someClass").classed("hide", false);
}
function mouseout(p){
d3.selectAll("circle.someClass").classed("hide", true);
}
function click(p){
d3.selectAll("circle.someClass").classed("hide", false);
}
If you plan to only have one element that controls the circle, use a "flag". Messing with conditionally registering/unregistering events is not a good idea.
Check this updated version of your fiddle:
https://jsfiddle.net/cze9rqf7/
var svg = d3.select("#content")
.append("svg")
.attr("width", 600)
.attr("height", 400);
var g = svg.append("g");
var text = g.append("text")
.text("Click me")
.style("fill", "Blue")
.attr("x", 50)
.attr("y", 50)
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.on("click", click);
var circle = g.append("circle")
.style("fill", "Orange")
.attr("cx", 150)
.attr("cy", 90)
.attr("r", 15)
.classed("hide", true)
.classed("someClass", true);
var isClicked = false;
function mouseover(p){
d3.selectAll("circle.someClass").classed("hide", false);
}
function mouseout(p){
if(!isClicked) {
d3.selectAll("circle.someClass").classed("hide", true);
}
}
function click(p){
isClicked = !isClicked;
d3.selectAll("circle.someClass").classed("hide", false);
}
EDITS For Comments
If you need to "remember" state per element, instead of using a global, you should be using data-binding on those elements:
var text = g.append("text")
.datum({isClicked: false})
.text("Click me")
...
function mouseout(p){
// p is the data-bound object
if(!p.isClicked) {
var className = d3.select(this).attr("class");
d3.selectAll("circle."+className).classed("hide", true);
}
}
function click(p){
// on click edit the data-bound object
p.isClicked = !p.isClicked;
var className = d3.select(this).attr("class");
d3.selectAll("circle."+className).classed("hide", false);
}
Updated fiddle here.
Here is an answer without any "flag":
Given that you have many labels, one option is removing the mouseout for the clicked element:
d3.select(this).on("mouseout", null);
Here is your updated fiddle: https://jsfiddle.net/gerardofurtado/38p18pLt/
And the same code in the Stack snippet:
var svg = d3.select("body")
.append("svg")
.attr("width", 600)
.attr("height", 400);
var g = svg.append("g");
var text = g.append("text")
.text("Click me")
.style("fill", "Blue")
.attr("x", 50)
.attr("y", 50)
.classed("someClass", true)
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.on("click", click);
var text2 = g.append("text")
.text("Click me")
.style("fill", "Blue")
.attr("x", 50)
.attr("y", 150)
.classed("someClass2", true)
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.on("click", click);
var circle = g.append("circle")
.style("fill", "Orange")
.attr("cx", 150)
.attr("cy", 90)
.attr("r", 15)
.classed("hide", true)
.classed("someClass", true);
var circle2 = g.append("circle")
.style("fill", "Green")
.attr("cx", 250)
.attr("cy", 90)
.attr("r", 15)
.classed("hide", true)
.classed("someClass2", true);
function mouseover(p) {
var className = d3.select(this).attr("class");
d3.selectAll("circle." + className).classed("hide", false);
}
function mouseout(p) {
var className = d3.select(this).attr("class");
d3.selectAll("circle." + className).classed("hide", true);
}
function click(p) {
d3.select(this).on("mouseout", null);
var className = d3.select(this).attr("class");
d3.selectAll("circle." + className).classed("hide", false);
}
.hide {
display: none;
}
text {
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
You can also toggle the click, making the mouseout work again:
if(d3.select(this)[0][0].__onmouseout){
d3.select(this).on("mouseout", null);
} else {
d3.select(this).on("mouseout", mouseout);
}
Here is the fiddle with the "toggle" function: https://jsfiddle.net/gerardofurtado/4zb9gL9r/1/
And the same code in the Stack snippet:
var svg = d3.select("body")
.append("svg")
.attr("width", 600)
.attr("height", 400);
var g = svg.append("g");
var text = g.append("text")
.text("Click me")
.style("fill", "Blue")
.attr("x", 50)
.attr("y", 50)
.classed("someClass", true)
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.on("click", click);
var text2 = g.append("text")
.text("Click me")
.style("fill", "Blue")
.attr("x", 50)
.attr("y", 150)
.classed("someClass2", true)
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.on("click", click);
var circle = g.append("circle")
.style("fill", "Orange")
.attr("cx", 150)
.attr("cy", 90)
.attr("r", 15)
.classed("hide", true)
.classed("someClass", true);
var circle2 = g.append("circle")
.style("fill", "Green")
.attr("cx", 250)
.attr("cy", 90)
.attr("r", 15)
.classed("hide", true)
.classed("someClass2", true);
function mouseover(p) {
var className = d3.select(this).attr("class");
d3.selectAll("circle." + className).classed("hide", false);
}
function mouseout(p) {
var className = d3.select(this).attr("class");
d3.selectAll("circle." + className).classed("hide", true);
}
function click(p) {
if (d3.select(this)[0][0].__onmouseout) {
d3.select(this).on("mouseout", null);
} else {
d3.select(this).on("mouseout", mouseout);
}
var className = d3.select(this).attr("class");
d3.selectAll("circle." + className).classed("hide", false);
}
.hide {
display: none;
}
text {
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

D3 Javascript - Only showing one link in force layout

I'm trying to create something that allows the user to scroll through an array of different links. The nodes stay the same, but the links change when the user clicks to see the next one.
However, it only shows one link in each array. Some arrays only have one link so that's okay, but the ones with more than one link need to be displayed correctly.
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
//var links = <?php echo json_encode(array_slice($data["links"], 0, 1)); ?>;
var links = <?php echo json_encode($links); ?>;
var nodes = <?php echo json_encode($nodes); ?>;
var count = <?php echo count($data); ?>;
var data_set = <?php echo json_encode($data); ?>;
//console.log(data_set);
//document.getElementById("demo").innerHTML = links;
max_count = links.length;
function draw()
{
function update_clique_view(direction)
{
geo_long_12_index += direction;
if(geo_long_12_index > max_count)
geo_long_12_index = 0;
else if(geo_long_12_index < 0)
geo_long_12_index = max_count - 1;
current_clique = links[geo_long_12_index];
d3.select("#link_number").remove();
svg.append("text")
.attr("id", "link_number")
.attr("x", width/2)
.attr("y", 20)
.attr("dy", ".35em")
.attr("opacity", 0.7)
.style("fill", "#FFFFFF")
.text(geo_long_12_index);
console.log(current_clique);
link.data(current_clique);
force.links(current_clique);
force.start();
}
var width = 800,
height = 600;
geo_long_12_index = 0;
if(links.length > 0)
{
current_clique = links[geo_long_12_index];
}
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
svg.append("rect")
.attr("width", "100%")
.attr("height", "100%")
.attr("rx", "20")
.attr("ry", "20")
.style("fill", "#000022")
.attr("class", "background");
svg.append("text")
.attr("id", "link_number")
.attr("x", width/2)
.attr("y", 20)
.attr("dy", ".35em")
.attr("opacity", 0.7)
.style("fill", "#FFFFFF")
.text(geo_long_12_index);
// Navigation arrows
var leftarrow = svg.append("svg:image")
.attr("xlink:href", "/cgi-bin/images/left_arrow.svg")
.attr("width", 20)
.attr("height", 20)
.attr("x", (width / 2) - 25)
.attr("y",20)
.attr("opacity", 0.7)
.on("click", function(d,i) {update_clique_view(-1);})
.on("mouseover", function(d) {d3.select(this).attr("opacity", 1);})
.on("mouseout", function(d) {d3.select(this).attr("opacity", 0.7);});
var rightarrow = svg.append("svg:image")
.attr("xlink:href","/cgi-bin/images/right_arrow.svg")
.attr("width", 20)
.attr("height", 20)
.attr("x", (width / 2) + 35)
.attr("y",20)
.attr("opacity", 0.7)
.on("click", function(d,i) {update_clique_view(1);})
.on("mouseover", function(d) {d3.select(this).attr("opacity", 1);})
.on("mouseout", function(d) {d3.select(this).attr("opacity", 0.7);});
var position_label = svg.append("text")
.attr("x", 10)
.attr("y", 30);
var force = d3.layout.force()
.gravity(.05)
.distance(100)
.charge(-100)
.size([width, height]);
force
.nodes(nodes)
.links(current_clique)
.start();
var link = svg.selectAll(".link")
.data(current_clique)
.enter().append("line")
.style("stroke", function(d) { return d.colour; })
.attr("class", "link");
var node = svg.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r", 5)
.style("fill", function(d) { return d.colour; })
.attr("class", "planet")
.on("mouseover", function(d) {d3.select(this).attr("r", 10);})
.on("mouseout", function(d) {d3.select(this).attr("r", 5);});
node.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(function(d) { return d.name });
force.on("tick", function() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
});
}
draw();
</script>
var links = [[{"source":17,"target":22,"orb":0.058311111111109,"colour":"grey"}],[{"source":20,"target":21,"orb":0.2079,"colour":"grey"}],[{"source":12,"target":15,"orb":0.70274999999998,"colour":"grey"}],[{"source":3,"target":21,"orb":1.0416277777778,"colour":"grey"}],[{"source":8,"target":12,"orb":0.46322777777775,"colour":"grey"},{"source":8,"target":15,"orb":0.23952222222223,"colour":"grey"},{"source":12,"target":15,"orb":0.70274999999998,"colour":"grey"}],[{"source":0,"target":17,"orb":0.71342777777778,"colour":"grey"},{"source":0,"target":22,"orb":0.77173888888888,"colour":"grey"},{"source":17,"target":22,"orb":0.058311111111109,"colour":"grey"}],[{"source":11,"target":14,"orb":-1.6950111111111,"colour":"grey"}],[{"source":8,"target":12,"orb":0.46322777777775,"colour":"grey"},{"source":7,"target":8,"orb":0.41579999999996,"colour":"grey"},{"source":7,"target":12,"orb":-0.047427777777784,"colour":"grey"},{"source":7,"target":15,"orb":0.6553222222222,"colour":"grey"},{"source":8,"target":15,"orb":0.23952222222223,"colour":"grey"},{"source":12,"target":15,"orb":0.70274999999998,"colour":"grey"}],[{"source":2,"target":16,"orb":1.3296555555555,"colour":"grey"},{"source":2,"target":18,"orb":0.2764,"colour":"grey"},{"source":16,"target":18,"orb":-1.0532555555556,"colour":"grey"}],[{"source":8,"target":12,"orb":0.46322777777775,"colour":"grey"},{"source":4,"target":7,"orb":-0.53862777777772,"colour":"grey"},{"source":4,"target":8,"orb":-0.12282777777776,"colour":"grey"},{"source":4,"target":12,"orb":-0.5860555555555,"colour":"grey"},{"source":4,"target":15,"orb":0.11669444444448,"colour":"grey"},{"source":7,"target":8,"orb":0.41579999999996,"colour":"grey"},{"source":7,"target":12,"orb":-0.047427777777784,"colour":"grey"},{"source":7,"target":15,"orb":0.6553222222222,"colour":"grey"},{"source":8,"target":15,"orb":0.23952222222223,"colour":"grey"},{"source":12,"target":15,"orb":0.70274999999998,"colour":"grey"}],[{"source":2,"target":13,"orb":0.94762777777777,"colour":"grey"},{"source":2,"target":16,"orb":1.3296555555555,"colour":"grey"},{"source":2,"target":18,"orb":0.2764,"colour":"grey"},{"source":13,"target":16,"orb":-0.38202777777778,"colour":"grey"},{"source":13,"target":18,"orb":-0.67122777777777,"colour":"grey"},{"source":16,"target":18,"orb":-1.0532555555556,"colour":"grey"}],[{"source":2,"target":13,"orb":0.94762777777777,"colour":"grey"},{"source":2,"target":19,"orb":-1.8974666666667,"colour":"grey"},{"source":13,"target":19,"orb":2.8450944444444,"colour":"grey"}],[{"source":11,"target":20,"orb":-2.9160166666667,"colour":"grey"},{"source":11,"target":21,"orb":-2.7081166666667,"colour":"grey"},{"source":20,"target":21,"orb":0.2079,"colour":"grey"}],[{"source":3,"target":9,"orb":-2.1064388888889,"colour":"grey"},{"source":3,"target":20,"orb":0.83372777777777,"colour":"grey"},{"source":9,"target":20,"orb":-2.9401666666667,"colour":"grey"}],[{"source":2,"target":9,"orb":2.9672611111111,"colour":"grey"},{"source":2,"target":13,"orb":0.94762777777777,"colour":"grey"},{"source":2,"target":16,"orb":1.3296555555555,"colour":"grey"},{"source":2,"target":18,"orb":0.2764,"colour":"grey"},{"source":9,"target":13,"orb":2.0196333333333,"colour":"grey"},{"source":9,"target":16,"orb":1.6376055555556,"colour":"grey"},{"source":9,"target":18,"orb":2.6908611111111,"colour":"grey"},{"source":13,"target":16,"orb":-0.38202777777778,"colour":"grey"},{"source":13,"target":18,"orb":-0.67122777777777,"colour":"grey"},{"source":16,"target":18,"orb":-1.0532555555556,"colour":"grey"}],[{"source":2,"target":5,"orb":-2.4144611111111,"colour":"grey"},{"source":2,"target":6,"orb":1.3803722222222,"colour":"grey"},{"source":2,"target":18,"orb":0.2764,"colour":"grey"},{"source":2,"target":19,"orb":-1.8974666666667,"colour":"grey"},{"source":5,"target":6,"orb":-1.0340888888889,"colour":"grey"},{"source":5,"target":18,"orb":2.6908611111111,"colour":"grey"},{"source":5,"target":19,"orb":-0.51699444444445,"colour":"grey"},{"source":6,"target":18,"orb":1.6567722222222,"colour":"grey"},{"source":6,"target":19,"orb":-0.51709444444444,"colour":"grey"},{"source":18,"target":19,"orb":2.1738666666667,"colour":"grey"}],[{"source":1,"target":2,"orb":-1.2271277777778,"colour":"grey"},{"source":1,"target":6,"orb":-2.6075,"colour":"grey"},{"source":1,"target":13,"orb":-0.27950000000001,"colour":"grey"},{"source":1,"target":16,"orb":0.10252777777777,"colour":"grey"},{"source":1,"target":18,"orb":-0.95072777777779,"colour":"grey"},{"source":2,"target":6,"orb":1.3803722222222,"colour":"grey"},{"source":2,"target":13,"orb":0.94762777777777,"colour":"grey"},{"source":2,"target":16,"orb":1.3296555555555,"colour":"grey"},{"source":2,"target":18,"orb":0.2764,"colour":"grey"},{"source":6,"target":13,"orb":2.328,"colour":"grey"},{"source":6,"target":16,"orb":2.7100277777778,"colour":"grey"},{"source":6,"target":18,"orb":1.6567722222222,"colour":"grey"},{"source":13,"target":16,"orb":-0.38202777777778,"colour":"grey"},{"source":13,"target":18,"orb":-0.67122777777777,"colour":"grey"},{"source":16,"target":18,"orb":-1.0532555555556,"colour":"grey"}],[{"source":1,"target":2,"orb":-1.2271277777778,"colour":"grey"},{"source":1,"target":9,"orb":1.7401333333333,"colour":"grey"},{"source":1,"target":13,"orb":-0.27950000000001,"colour":"grey"},{"source":1,"target":16,"orb":0.10252777777777,"colour":"grey"},{"source":1,"target":18,"orb":-0.95072777777779,"colour":"grey"},{"source":2,"target":9,"orb":2.9672611111111,"colour":"grey"},{"source":2,"target":13,"orb":0.94762777777777,"colour":"grey"},{"source":2,"target":16,"orb":1.3296555555555,"colour":"grey"},{"source":2,"target":18,"orb":0.2764,"colour":"grey"},{"source":9,"target":13,"orb":2.0196333333333,"colour":"grey"},{"source":9,"target":16,"orb":1.6376055555556,"colour":"grey"},{"source":9,"target":18,"orb":2.6908611111111,"colour":"grey"},{"source":13,"target":16,"orb":-0.38202777777778,"colour":"grey"},{"source":13,"target":18,"orb":-0.67122777777777,"colour":"grey"},{"source":16,"target":18,"orb":-1.0532555555556,"colour":"grey"}]];
var nodes = [{"name":"EARTHSUN","colour":"darkgreen"},{"name":"MERCURY","colour":"cyan"},{"name":"VENUS","colour":"magenta"},{"name":"MARS","colour":"red"},{"name":"JUPITER","colour":"gold"},{"name":"SATURN","colour":"darkslategray"},{"name":"URANUS","colour":"blue"},{"name":"NEPTUNE","colour":"blueviolet"},{"name":"PLUTO","colour":"maroon"},{"name":"CHIRON","colour":"orange"},{"name":"CERES","colour":"sandybrown"},{"name":"JUNO","colour":"orchid"},{"name":"PALLAS","colour":"royalblue"},{"name":"VESTA","colour":"pink"},{"name":"SAPPHO","colour":"plum"},{"name":"SEDNA","colour":"slategray"},{"name":"MARSSATURN","colour":null},{"name":"JUPITERSATURN","colour":"brown"},{"name":"SATURNCHIRON","colour":"indianred"},{"name":"SATURNURANUS","colour":null},{"name":"SATURNNEPTUNE","colour":null},{"name":"SATURNPLUTO","colour":null},{"name":"SATURNSEDNA","colour":null}];
Thanks for looking at this.

D3 force layout - .exit().remove() just giving back errors on tick event

I have a problem with link.exit().remove(); and node.exit().remove();. If I set it in the initializeGraph method then I get several errors with the tick function I think. So my question is how or why do I get those errors:
Uncaught TypeError: undefined is not a function graph-d3.js:156initializeGraph graph-d3.js:156updateForceUsingNewNodes graph-d3.js:108createGraph graph-d3.js:18$.ajax.success ajax-stuff.js:106j jquery-2.1.1.min.js:2k.fireWith jquery-2.1.1.min.js:2x jquery-2.1.1.min.js:4n.prop.on.c jquery-2.1.1.min.js:4n.event.dispatch jquery-2.1.1.min.js:3r.handle jquery-2.1.1.min.js:3
3Error: Invalid value for <line> attribute x1="NaN" d3.min.js:1
3Error: Invalid value for <line> attribute y1="NaN" d3.min.js:1
3Error: Invalid value for <line> attribute x2="NaN" d3.min.js:1
3Error: Invalid value for <line> attribute y2="NaN" d3.min.js:1
Uncaught TypeError: Cannot read property 'attr' of undefined
Here is an exerpt of the source code. Not important lines are removed:
var alreadyThere = false;
var nodeCircles = {};
var svg, link, node;
var force = d3.layout.force();
var width = 700, height = 200;
var boxIDName = "#main-rightinfo";
var currentJSON;
var container;
var zoom = d3.behavior.zoom()
.scaleExtent([0.4, 5]);
var drag = force.drag();
function createGraph(newJSON){
if (alreadyThere){
svg.remove();
nodeCircles = {};
}
updateForceUsingNewNodes(generateObjects(newJSON));
alreadyThere = true;
currentJSON = newJSON;
force.start();
}
function updateGraph(newJSON){
svg.remove();
findDuplicatesAndSetEmpty(newJSON);
deleteEmptyObjectsInJSON(newJSON);
currentJSON = currentJSON.concat(newJSON);
updateForceUsingNewNodes(generateObjects(currentJSON));
force.start();
}
//here are some methods forming the json and array...
function initializeGraph(){
zoom.on("zoom", zoomed);
drag.on("dragstart", dragstart);
force
.size([width, height])
.gravity(.1)
.charge(-400)
.friction(0.9)
.theta(0.9)
.linkStrength(0.9)
.distance(55)
.alpha(0.1)
.on("tick", tick);
svg = d3.select("#main-right")
.append("svg")
.attr("width", width)
.attr("height", height)
.call(zoom).on("dblclick.zoom", null);
svg
.append("svg:defs").selectAll("marker")
.data(["end"])
.enter().append("svg:marker")
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 32)
.attr("refY", -0.05)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5")
.attr('fill', '#359AF4');
container = svg.append("g");
link = container.append("g")
.attr("class", "links")
.selectAll(".link")
.data(force.links())
.enter().append("line")
.attr("class", "link")
.attr("marker-end", "url(#end)");
node = container.append("g")
.attr("class", "nodes")
.selectAll(".node")
.data(force.nodes())
.enter().append("g")
.attr("class", "node")
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.on("click", function(d) { click(d); })
.on("dblclick", function(d) { dblclick(d); })
.on('contextmenu', function(data, index) {
d3.event.preventDefault();
updateGraphByRemoveElement(data, index);
})
.call(drag);
node
.append("circle")
.attr("r", 20)
.attr("cx", 0)
.attr("cy", 0)
.style("fill", '#eee')
.style("stroke", '#fff')
.style("stroke-width", '0.5px');
node
.append("image")
.attr("xlink:href", function(d) {
if (d.class == "Person") {
return "pics/node_person.svg";
} else {
return "pics/node_appln.svg";
}} )
.attr("x", -20)
.attr("y", -20)
.attr("width", 40)
.attr("height", 40)
.attr("color", "white");
node
.append("text")
.attr("x", 20)
.attr("y", 4)
.style("fill", "#bbb")
.text(function(d) { return d.name; });
node
.append("circle")
.attr("r", 7)
.attr("cx", 0)
.attr("cy", -16)
.style("fill", '#359AF4');
node
.append("text")
.attr("text-anchor", "center")
.attr("x", -3)
.attr("y", -13)
.style("fill", "white")
.text(function(d) { return d.linkCount; });
function tick() {
link
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
}
}
//here are some functions tick, mousedown and so on...
Well as you can see the svg.remove(); from the code is not needed. But until the exit().remove() do not work, it's needed. So yeah how to handle that with the tickevent/ .exit().remove().
Thank you for any tips.
PS: I used this very basic one https://gist.github.com/mbostock/1095795
and another which is very close to mine D3.js - exit() section does not remove all data
and this working not working, too Why does d3.js v3 break my force graph when implementing zooming when v2 doesn't?
Whole code or let's say how I think it should run, but currently getting some errors (not identical to the code above, but just changed some lines)
var alreadyThere = false;
var nodeCircles = {};
var svg, link, node;
var force = d3.layout.force();
var width = 700, height = 400;
var boxIDName = "#main-rightinfo";
var currentJSON;
var container;
var zoom = d3.behavior.zoom()
.scaleExtent([0.4, 5]);
var drag = force.drag();
function createGraph(newJSON){
if (alreadyThere){
//svg.remove();
nodeCircles = {};
}
updateForceUsingNewNodes(generateObjects(newJSON));
alreadyThere = true;
currentJSON = newJSON;
force.start();
}
function updateGraph(newJSON){
//svg.remove();
findDuplicatesAndSetEmpty(newJSON);
deleteEmptyObjectsInJSON(newJSON);
currentJSON = currentJSON.concat(newJSON);
updateForceUsingNewNodes(generateObjects(currentJSON));
force.start();
}
function findDuplicatesAndSetEmpty(newJSON){
for (var i = 0; i < currentJSON.length; i++) {
for (var o = 0; o < newJSON.length; o++) {
if ((currentJSON[i].source.ID == newJSON[o].source) && (currentJSON[i].target.ID == newJSON[o].target)
|| (currentJSON[i].source.ID == newJSON[o].target) && (currentJSON[i].target.ID == newJSON[o].source)){
newJSON[o] = {};
}
}
}
}
function deleteEmptyObjectsInJSON(json){
for (var i = 0; i < json.length; i++) {
var y = json[i].source;
if (y==="null" || y===null || y==="" || typeof y === "undefined"){
json.splice(i,1);
i--;
}
}
}
function updateGraphByRemoveElement(clickedNode, index){
svg.remove();
var json4Splicing = currentJSON;
for (var i = 0; i < json4Splicing.length; i++) {
if (json4Splicing[i].source.ID == clickedNode.ID){
json4Splicing[i] = {};
} else if (json4Splicing[i].target.ID == clickedNode.ID){
json4Splicing[i] = {};
}
}
deleteEmptyObjectsInJSON(json4Splicing);
deleteNode(force.nodes(),clickedNode);
currentJSON = json4Splicing;
updateForceRemoveElement(generateObjects(currentJSON));
}
function deleteNode(allNodes, clickedNode){
allNodes.forEach(function(node) {
if (node == clickedNode){
force.links().forEach(function(link) {
if (node.ID == link.source.ID){
link.target.linkCount--;
}
if (node.ID == link.target.ID){
link.source.linkCount--;
}
});
node.linkCount = 0;
}
});
}
function generateObjects(json) {
json.forEach(function(link) {
if (typeof(link.source) == "string"){
link.source = nodeCircles[link.source] || (nodeCircles[link.source] = {name: link.sourceName, ID: link.source, class: link.sourceClass, linkCount:0});
link.source.linkCount++;
}
if (typeof(link.target) == "string"){
link.target = nodeCircles[link.target] || (nodeCircles[link.target] = {name: link.targetName, ID: link.target, class: link.targetClass, linkCount:0});
link.target.linkCount++;
}
});
return json;
}
function updateForceRemoveElement(links){
force.nodes(d3.values(nodeCircles).filter(function(d){ return d.linkCount; }) );
force.links(d3.values(links));
initializeGraph();
}
function updateForceUsingNewNodes(links){
force.nodes(d3.values(nodeCircles).filter(function(d){ return d.linkCount; }) );
force.links(d3.values(links));
initializeGraph();
}
function initializeGraph(){
zoom.on("zoom", zoomed);
drag.on("dragstart", dragstart);
force
.size([width, height])
.gravity(.1)
.charge(-400)
.friction(0.9)
.theta(0.9)
.linkStrength(0.9)
.distance(55)
.alpha(0.1)
.on("tick", tick);
svg = d3.select("#main-right")
.append("svg")
.attr("width", width)
.attr("height", height)
.call(zoom).on("dblclick.zoom", null);
svg
.append("svg:defs").selectAll("marker")
.data(["end"])
.enter().append("svg:marker")
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 32)
.attr("refY", -0.05)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5")
.attr('fill', '#359AF4');
container = svg.append("g");
link = container.append("g")
.attr("class", "links")
.selectAll(".link")
.data(force.links())
.enter().append("line")
.attr("class", "link")
.attr("marker-end", "url(#end)");
link.exit().remove();
node = container.append("g")
.attr("class", "nodes")
.selectAll(".node")
.data(force.nodes())
.enter().append("g")
.attr("class", "node")
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.on("click", function(d) { click(d); })
.on("dblclick", function(d) { dblclick(d); })
.on('contextmenu', function(data, index) {
d3.event.preventDefault();
updateGraphByRemoveElement(data, index);
})
.call(drag);
node
.append("circle")
.attr("r", 20)
.attr("cx", 0)
.attr("cy", 0)
.style("fill", '#eee')
.style("stroke", '#fff')
.style("stroke-width", '0.5px');
node
.append("image")
.attr("xlink:href", function(d) {
if (d.class == "Person") {
return "pics/node_person.svg";
} else {
return "pics/node_appln.svg";
}} )
.attr("x", -20)
.attr("y", -20)
.attr("width", 40)
.attr("height", 40)
.attr("color", "white");
node
.append("text")
.attr("x", 20)
.attr("y", 4)
.style("fill", "#bbb")
.text(function(d) { return d.name; });
node
.append("circle")
.attr("r", 7)
.attr("cx", 0)
.attr("cy", -16)
.style("fill", '#359AF4');
node
.append("text")
.attr("text-anchor", "center")
.attr("x", -3)
.attr("y", -13)
.style("fill", "white")
.text(function(d) { return d.linkCount; });
node.exit().remove();
}
function tick() {
link
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
}
d3.selection.prototype.moveToFront = function() {
return this.each(function(){
this.parentNode.appendChild(this);
});
};
function zoomed() {
d3.event.sourceEvent.stopPropagation();
container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
function dragstart(d) {
d3.event.sourceEvent.stopPropagation();
d3.select(this).classed("fixed", d.fixed = true);
}
function mouseover() {
d3.select(this).select("text").transition()
.duration(750)
.style("font-size","15px")
.style("fill","black");
d3.select(this).moveToFront();
}
function mouseout() {
d3.select(this).select("text").transition()
.duration(750)
.style("font-size","10px")
.style("fill","#ccc");
}
function click(d) {
$(boxIDName).empty();
if (d.class == "Person"){
$(boxIDName).append("<h2>Person/Company</h2>");
getNodeInfoPerson(d.ID);
}
if (d.class == "Appln"){
$(boxIDName).append("<h2>Application</h2>");
getNodeInfoAppln(d.ID);
}
}
function dblclick(d) {
entryClicked(d.ID+"|"+d.class,false);
}

Categories

Resources