I have created a D3Js vertical collapsible tree by taking the code from this site. I want to increase the radius of the nodes. Currently, its at r=10 and would like to increase it to 30. Which results the neighbour nodes to overlap with each other like below.. How can I increase the distance between each node so it doesnt overlap with each other?
Thank you
function buildVerticalTree(treeData,treeContainerDom){
var margin = {top :40,right:120,bottom:20,left:120};
var width = 960 - margin.right - margin.left;
var height = 700 - margin.top - margin.bottom;
var i = 0, duration = 750;
var tree = d3.layout.tree()
.size([height,width]);
var diagonal = d3.svg.diagonal()
.projection(function(d){
return [d.x, d.y];
});
var svg = d3.select(treeContainerDom).append("svg")
.attr("width",width+margin.left+margin.right)
.attr("height",height+margin.top+margin.bottom)
.append("g")
.attr("transform","translate("+margin.left+","+margin.top+")");
var root = treeData;
update(root);
function update(source){
var nodes = tree.nodes(root).reverse();
var links = tree.links(nodes);
nodes.forEach(function(d){
d.y = d.depth * 100;
});
var node = svg.selectAll("g.node")
.data(nodes,function(d){
return d.id || (d.id=++i);
});
var nodeEnter = node.enter().append("g")
.attr("class","node")
.attr("transform",function(d){
if(!source.x0 && !source.y0)
return "";
return "translate("+source.x0+","+source.y0+")";
})
.on("click",nodeclick)
nodeEnter.append("circle")
.attr("r",10)
.attr("stroke",function(d){
return d.children || d._children ? "steelblue" : "#00c13f";
})
.style("fill",function(d){
return d.children || d._children ? "lightsteelblue" : "#fff";
});
nodeEnter.append("text")
.attr("y",function(d){
return d.children || d._children ? -18 : 18;
//return 0;
})
.attr("dy",".35em")
.attr("text-anchor","middle")
.text(function(d){
return d.name;
})
.style("fill","black")
.style("fill-opacity",1e-6)
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform",function(d){
return "translate("+ d.x+","+ d.y+")";
});
nodeUpdate.select("circle")
.attr("r",10)
.style("fill",function(d){
return d._children ? "lightsteelblue" : "#fff";
});
nodeUpdate.select("text")
.style("fill-opacity",1);
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform",function(d){
return "translate("+source.x+","+source.y+")";
})
.remove();
nodeExit.select("circle")
.attr("r",1e-6);
nodeExit.select("text")
.style("fill-opacity",1e-6);
var link = svg.selectAll("path.link")
.data(links,function(d){
return d.target.id;
});
link.enter().insert("path","g")
.attr("class","link")
.attr("d",function(d){
if(!source.x0 && !source.y0)
return "";
var o = {x:source.x0,y:source.y0};
return diagonal({source:o,target:o});
});
link.transition()
.duration(duration)
.attr("d",diagonal);
link.exit().transition()
.duration(duration)
.attr("d",function(d){
var o = {x:source.x,y:source.y};
return diagonal({source:o,target:o});
})
.remove();
nodes.forEach(function(d){
d.x0 = d.x;
d.y0 = d.y;
});
}
function nodeclick(d){
if(d.children){
d._children = d.children;
d.children = null;
}else{
d.children = d._children;
d._children = null;
}
update(d);
}
}//end of buildVerticalTree
buildVerticalTree(that.objectList, "#tree");
Related
The sample JSON file containing the data looks like this :
services {
service name1: []
exposed interfaces: []
consumed interfaces: []
},
{
service name2: []
exposed interfaces: []
consumed interfaces: []
},
{
service name3: []
exposed interfaces: []
consumed interfaces: []
}
interfaces {
interface name1:
protocol stack:[]
},
interfaces {
interface name1:
protocol stack:[]
},
interfaces {
interface name1:
protocol stack:[]
}
I am trying to connect the services with their consumed interfaces, and exposed interfaces and the problem I am facing is with links, I am either able to connect only a few of the links of the services and other services and nodes are left without any connections even if they are related with interfaces and due this i guess force simulation is also not working and all the nodes are just lying in the center, the code here is as follows:
```
// set the dimensions and margins of the graph
var margin = {top: 10, right: 10, bottom: 10, left: 30},
width = 1200 - margin.left - margin.right,
height = 700 - margin.top - margin.bottom;
servicesColor = "green"
interfacesColor = "brown"
inputColor = "blue"
outputColor = "pink"
var sourceData = {}
suggestionsElement = document.getElementById("suggestions")
function dataPreProcessing(data){
console.log("processing the services");
data.services = data.services.map(d => {
d.type = "services"
d.id=d.name
d.clickToggle = false;
return d;
});
console.log("processing the interfaces");
data.interfaces = data.interfaces.map(d => {
d.type = "interfaces"
d.id=d.name
d.clickToggle = false;
return d;
});
data.nodes = data.services;
data.nodes = data.nodes.concat(data.interfaces);
data.links=[]
data.nodes.forEach(d=>{
if(d.type ==="services"){
d.exposedInterfaces.forEach(b=>{
data.links.push(
{
"source": b,
"target": d.id
}
)
})
d.consumedInterfaces.forEach(b=>{
data.links.push(
{
"source": d.id,
"target": b
}
)
})
}
})
return data;
}
function visualize(data) {
//dataPreProcessing(data);
// Initialize the links
// append the svg object to the body of the page
var svg = d3.select("#vizBox")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom).call(d3.zoom().on("zoom",
function () {
svg.attr("transform", d3.event.transform)
}))
.append("g");
// Let's list the force we wanna apply on the network
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) { return d.id; }))
.force("charge", d3.forceManyBody().strength(-500))
.force("center", d3.forceCenter(width / 2, height / 2));
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
simulation.force("link", null).force("charge", null).force("center", null);
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d3.event.x = null;
d3.event.fy = null;
}
// tooltip
tooltip = d3.select("body").append("div").style("width","fit-
content").style("height","auto").style("background","#f8f8f8")
.style("opacity","1").style("position","absolute").style("visibility","hidden").style("box-
shadow","0px 0px 6px #7861A5").style("padding","10px");
var link = svg
.selectAll("line")
.data(data.links)
.enter()
.append("line")
.style("stroke", "black")
// Initialize the nodes
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("g")
.data(data.nodes)
.enter().append("g");
var circles = node.append("circle")
.attr("r", 10)
.attr("fill",function(d){return d.type==="services"? servicesColor:
interfacesColor});
// Create a drag handler and append it to the node object instead
var drag_handler = d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended);
drag_handler(node);
var lables = node.append("text")
.text(function(d) {
return d.id;
})
.attr('x', 12)
.attr('y', 3);
node.on("click", (d) => {
if(!d.clickToggle){
tooltip.style("visibility","visible")
.style("top",(d3.event.pageY-30)+"px").style("left",(d3.event.pageX+20)+"px");
let aTags = d.type === "services" ? "<a Source Documentation</a> <br/>": "";
let htmlValue = "<strong>Name: </strong>"+d.name+"<br/><strong>Type:
</strong>"+d.type+" <br/>"+aTags+"<strong>JSON:</strong> <br/><div style=\"width: 300px;
height: 300px; overflow: scroll;\"><pre><code >"+hljs.highlightAuto(JSON.stringify(d,null,
2)).value+"</code></pre></div>";
tooltip.html(htmlValue);
d.clickToggle = true;
}
else{
tooltip.style("visibility","hidden");
d.clickToggle = false;
}
if(d.type == "services"){
svg.selectAll("circle").style("fill", (iterNode)=>{
if(d.exposedInterfaces.length == 0){
iterNode.inUse = false;
return iterNode.type=== "services"? servicesColor: interfacesColor;
}
if(d.exposedInterfaces.some((x) => x == iterNode.id)){
iterNode.inUse = true;
return outputColor;
}else{
iterNode.inUse = false;
return iterNode.type=== "services"? servicesColor: interfacesColor;
}
});
svg.selectAll("circle").style("fill", (iterNode)=>{
if( iterNode.inUse){
return outputColor;
}
if(d.consumedInterfaces.length == 0){
return iterNode.type=== "services"? servicesColor: interfacesColor;
}
if(d.consumedInterfaces.some((x) => x == iterNode.id)){
return inputColor;
}else{
return iterNode.type=== "services"? servicesColor: interfacesColor;
}
});
}
})
simulation
.nodes(data.nodes)
.on("tick", ticked);
simulation.force("link")
.links(data.links);
function ticked() {
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.json("/data/api.json",(data) => {
sourceData = data;
data = window.dataPreProcessing(data);
visualize(data);
});
function suggest(value){
filteredData = [];
if(!!value){
filteredData = sourceData.nodes.filter((d)=> {
return d.name.toLowerCase().indexOf(value.toLowerCase()) >= 0;
})
}
filteredData = filteredData.slice(0, 3);
console.log(filteredData, value, filteredData.length);
if(filteredData.length === 0){
d3.select("#suggestions").html("");
d3.select("#suggestions").style("opacity", "0")
setVisibility("none");
return;
}
else{
d3.select("#suggestions").html("");
d3.select("#suggestions").selectAll("div")
.data(filteredData)
.enter()
.append("div")
.attr("id","suggestionItem")
.text((d)=> d.name).on("click",(d) => {
d3.select("#suggestions").html("");
SearchData = {};
SearchData.nodes = [d];
SearchData.links = [d.exposedInterfaces, d.consumedInterfaces];
d3.select("#vizBox").html("");
document.getElementById("searchInput").value = d.name;
visualize(SearchData);
});
}
}
function change(){
var value = document.getElementById("searchInput").value;
suggest(value);
setVisibility("block");
d3.select("#suggestions").style("opacity", "1")
}
function inputFocusOut(){
setVisibility("none");
d3.select("#suggestions").style("opacity", "0")
}
function setVisibility(value){
suggestionsElement.style.display= value;
}
function reset(){
d3.select("#vizBox").html("");
document.getElementById("searchInput").value = "";
setTimeout(d3.json("/data/api.json",(data) => {
data = dataPreProcessing(data);
visualize(sourceData);
}), 5000);
}
```
I want to change the color of nodes when clicking on it. It should be set in the "click" function.
However, in the click function, "d" is the node element, but to change node color I have to select the "circle" element, which is append to node using nodeEnter.append("circle"). How can I achieve it?
the html file:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 3px;
}
.node text {
font: 30px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 7px;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 20, right: 20, bottom: 20, left: 20},
width = 1200 - margin.right - margin.left,
height = 800 - margin.top - margin.bottom;
var i = 0,
duration = 750,
root;
var tree = d3.layout.tree();
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.x, d.y]; });
var svg = d3.select("body").append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.json("parse_tree.json", function(error, parse_tree) {
if (error) throw error;
root = parse_tree;
root.x0 = height / 2;
root.y0 = 0;
tree.size([width, height]);
update(root);
});
function update(source1) {
var originalConsole = console;
var nodes = tree.nodes(root);
var links = tree.links(nodes);
nodes.forEach(function(d) { d.y = d.depth * 100; });
// Update the nodes…
var node = svg.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source1.y0 + "," + source1.x0 + ")"; })
.on("click", click);
nodeEnter.append("circle")
.attr("r", 1e-6)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
nodeEnter.append("text")
.attr("x", function(d) { return d.children || d._children ? -20 : 20; })
.attr("dy", ".35em")
.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
.text(function(d) { return d.name; })
.style("fill-opacity", 1e-6);
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
nodeUpdate.select("circle")
.attr("r", 10)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
nodeUpdate.select("text")
.style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + source1.y + "," + source1.x + ")"; })
.remove();
nodeExit.select("circle")
.attr("r", 1e-6);
nodeExit.select("text")
.style("fill-opacity", 1e-6);
// Update the links…
var link = svg.selectAll("path.link")
.data(links, function(d) {
return d.target.id; }
);
// Enter any new links at the parent's previous position.
link.enter().insert("path", "g")
.attr("class", "link")
.attr("d", function(d) {
var o = {x: source1.x0, y: source1.y0};
return diagonal({source: o, target: o});
})
.style("stroke-width", "3px")
.style("stroke", "green");
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function(d) {
var o = {x: source1.x, y: source1.y};
return diagonal({source: o, target: o});
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
for(var k = 0; k < 1000; k++)
flag = 0;
}
// Toggle children on click.
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);
}
</script>
the json file:
{"name":"VP",
"size":"89",
"children": [
{"name":"VBP",
"size":"15",
"children":[{"name":"are", "size":"38"}]
},
{"name":"NP",
"size":"83",
"children": [
{"name":"DT",
"size":"29",
"children":[{"name":"a", "size":"53"}]
},
{"name":"NN",
"size":"50",
"children":[{"name":"boy", "size":"99"}]
}
]
}
]
}
d is the data, not the node
this in the click function is the dom node
d3.select(this) is the selection that picks just that node as a d3 selection
so to get a child circle element in a selection, you would do
d3.select(this).select("circle")
Now you'd think you'd just add a style("fill", "red") or whatever to this and job done, but as this is the oft-forked example from Mike Bostock that style would get overridden again in the transition update. So what you need to do is set a property on the data and then get that picked up by the drawing in the enter/update/exit sequence.
In the end all you need in the click function is:
d.clicked = true;
and in the nodeUpdate section do this -->
nodeUpdate.select("circle")
.attr("r", function(d){ return computeRadius(d); })
.style("fill", function(d) { return d.clicked ? "red" : (d._children ? "lightsteelblue" : "#fff");});
Note this doesn't do anything about un-highlighting a node. (You'd have to toggle the previous d.clicked boolean value)
i read lots of threads and the Mike's blog but i haven't found how to solve my problem.
I'm using the donut chart of D3.js and everything works fine.
I use that code and change the value for each diagram:
var w = 650;
var h = 400;
var r = 150;
var ir = 75;
var textOffset = 24;
var tweenDuration = 1050;
//OBJECTS TO BE POPULATED WITH DATA LATER
var lines, valueLabels, nameLabels;
var pieData = [];
var oldPieData = [];
var filteredPieData = [];
//D3 helper function to populate pie slice parameters from array data
var donut = d3.layout.pie().value(function(d){
return d.itemValue;
});
//D3 helper function to create colors from an ordinal scale
var color = d3.scale.category20c();
//D3 helper function to draw arcs, populates parameter "d" in path object
var arc = d3.svg.arc()
.startAngle(function(d){ return d.startAngle; })
.endAngle(function(d){ return d.endAngle; })
.innerRadius(ir)
.outerRadius(r);
///////////////////////////////////////////////////////////
// GENERATE FAKE DATA /////////////////////////////////////
///////////////////////////////////////////////////////////
var data;
var dataStructure = [
{
"data":[
{
"itemLabel":"Social Media",
"itemValue":90
},
{
"itemLabel":"Blogs",
"itemValue":30
},
{
"itemLabel":"Text Messaging",
"itemValue":60
},
{
"itemLabel":"Email",
"itemValue":90
},
],
"label":"2007"
},
{
"data":[
{
"itemLabel":"Social Media",
"itemValue":80
},
{
"itemLabel":"Blogs",
"itemValue":20
},
{
"itemLabel":"Text Messaging",
"itemValue":70
},
{
"itemLabel":"Email",
"itemValue":90
},
],
"label":"2009"
},
{
"data":[
{
"itemLabel":"Social Media",
"itemValue":70
},
{
"itemLabel":"Blogs",
"itemValue":20
},
{
"itemLabel":"Text Messaging",
"itemValue":70
},
{
"itemLabel":"Email",
"itemValue":90
},
],
"label":"2011"
},
{
"data":[
{
"itemLabel":"Social Media",
"itemValue":60
},
{
"itemLabel":"Blogs",
"itemValue":20
},
{
"itemLabel":"Text Messaging",
"itemValue":70
},
{
"itemLabel":"Email",
"itemValue":90
},
],
"label":"2013"
},
];
///////////////////////////////////////////////////////////
// CREATE VIS & GROUPS ////////////////////////////////////
///////////////////////////////////////////////////////////
var vis = d3.select("#pie-chart").append("svg:svg")
.attr("width", w)
.attr("height", h);
//GROUP FOR ARCS/PATHS
var arc_group = vis.append("svg:g")
.attr("class", "arc")
.attr("transform", "translate(" + (w/2) + "," + (h/2) + ")");
//GROUP FOR LABELS
var label_group = vis.append("svg:g")
.attr("class", "label_group")
.attr("transform", "translate(" + (w/2) + "," + (h/2) + ")");
//GROUP FOR CENTER TEXT
var center_group = vis.append("svg:g")
.attr("class", "center_group")
.attr("transform", "translate(" + (w/2) + "," + (h/2) + ")");
//PLACEHOLDER GRAY CIRCLE
// var paths = arc_group.append("svg:circle")
// .attr("fill", "#EFEFEF")
// .attr("r", r);
///////////////////////////////////////////////////////////
// CENTER TEXT ////////////////////////////////////////////
///////////////////////////////////////////////////////////
//WHITE CIRCLE BEHIND LABELS
var whiteCircle = center_group.append("svg:circle")
.attr("fill", "white")
.attr("r", ir);
///////////////////////////////////////////////////////////
// STREAKER CONNECTION ////////////////////////////////////
///////////////////////////////////////////////////////////
// to run each time data is generated
function update(number) {
data = dataStructure[number].data;
oldPieData = filteredPieData;
pieData = donut(data);
var sliceProportion = 0; //size of this slice
filteredPieData = pieData.filter(filterData);
function filterData(element, index, array) {
element.name = data[index].itemLabel;
element.value = data[index].itemValue;
sliceProportion += element.value;
return (element.value > 0);
}
//DRAW ARC PATHS
paths = arc_group.selectAll("path").data(filteredPieData);
paths.enter().append("svg:path")
.attr("stroke", "white")
.attr("stroke-width", 0.5)
.attr("fill", function(d, i) { return color(i); })
.transition()
.duration(tweenDuration)
.attrTween("d", pieTween);
paths
.transition()
.duration(tweenDuration)
.attrTween("d", pieTween);
paths.exit()
.transition()
.duration(tweenDuration)
.attrTween("d", removePieTween)
.remove();
//DRAW TICK MARK LINES FOR LABELS
lines = label_group.selectAll("line").data(filteredPieData);
lines.enter().append("svg:line")
.attr("x1", 0)
.attr("x2", 0)
.attr("y1", -r-3)
.attr("y2", -r-15)
.attr("stroke", "gray")
.attr("transform", function(d) {
return "rotate(" + (d.startAngle+d.endAngle)/2 * (180/Math.PI) + ")";
});
lines.transition()
.duration(tweenDuration)
.attr("transform", function(d) {
return "rotate(" + (d.startAngle+d.endAngle)/2 * (180/Math.PI) + ")";
});
lines.exit().remove();
//DRAW LABELS WITH PERCENTAGE VALUES
valueLabels = label_group.selectAll("text.value").data(filteredPieData)
.attr("dy", function(d){
if ((d.startAngle+d.endAngle)/2 > Math.PI/2 && (d.startAngle+d.endAngle)/2 < Math.PI*1.5 ) {
return 5;
} else {
return -7;
}
})
.attr("text-anchor", function(d){
if ( (d.startAngle+d.endAngle)/2 < Math.PI ){
return "beginning";
} else {
return "end";
}
})
.text(function(d){
var percentage = (d.value/sliceProportion)*100;
return percentage.toFixed(1) + "%";
});
valueLabels.enter().append("svg:text")
.attr("class", "value")
.attr("transform", function(d) {
return "translate(" + Math.cos(((d.startAngle+d.endAngle - Math.PI)/2)) * (r+textOffset) + "," + Math.sin((d.startAngle+d.endAngle - Math.PI)/2) * (r+textOffset) + ")";
})
.attr("dy", function(d){
if ((d.startAngle+d.endAngle)/2 > Math.PI/2 && (d.startAngle+d.endAngle)/2 < Math.PI*1.5 ) {
return 5;
} else {
return -7;
}
})
.attr("text-anchor", function(d){
if ( (d.startAngle+d.endAngle)/2 < Math.PI ){
return "beginning";
} else {
return "end";
}
}).text(function(d){
var percentage = (d.value/sliceProportion)*100;
return percentage.toFixed(1) + "%";
});
valueLabels.transition().duration(tweenDuration).attrTween("transform", textTween);
valueLabels.exit().remove();
//DRAW LABELS WITH ENTITY NAMES
nameLabels = label_group.selectAll("text.units").data(filteredPieData)
.attr("dy", function(d){
if ((d.startAngle+d.endAngle)/2 > Math.PI/2 && (d.startAngle+d.endAngle)/2 < Math.PI*1.5 ) {
return 17;
} else {
return 5;
}
})
.attr("text-anchor", function(d){
if ((d.startAngle+d.endAngle)/2 < Math.PI ) {
return "beginning";
} else {
return "end";
}
}).text(function(d){
return d.name;
});
nameLabels.enter().append("svg:text")
.attr("class", "units")
.attr("transform", function(d) {
return "translate(" + Math.cos(((d.startAngle+d.endAngle - Math.PI)/2)) * (r+textOffset) + "," + Math.sin((d.startAngle+d.endAngle - Math.PI)/2) * (r+textOffset) + ")";
})
.attr("dy", function(d){
if ((d.startAngle+d.endAngle)/2 > Math.PI/2 && (d.startAngle+d.endAngle)/2 < Math.PI*1.5 ) {
return 17;
} else {
return 5;
}
})
.attr("text-anchor", function(d){
if ((d.startAngle+d.endAngle)/2 < Math.PI ) {
return "beginning";
} else {
return "end";
}
}).text(function(d){
return d.name;
});
nameLabels.transition().duration(tweenDuration).attrTween("transform", textTween);
nameLabels.exit().remove();
}
///////////////////////////////////////////////////////////
// FUNCTIONS //////////////////////////////////////////////
///////////////////////////////////////////////////////////
// Interpolate the arcs in data space.
function pieTween(d, i) {
var s0;
var e0;
if(oldPieData[i]){
s0 = oldPieData[i].startAngle;
e0 = oldPieData[i].endAngle;
} else if (!(oldPieData[i]) && oldPieData[i-1]) {
s0 = oldPieData[i-1].endAngle;
e0 = oldPieData[i-1].endAngle;
} else if(!(oldPieData[i-1]) && oldPieData.length > 0){
s0 = oldPieData[oldPieData.length-1].endAngle;
e0 = oldPieData[oldPieData.length-1].endAngle;
} else {
s0 = 0;
e0 = 0;
}
var i = d3.interpolate({startAngle: s0, endAngle: e0}, {startAngle: d.startAngle, endAngle: d.endAngle});
return function(t) {
var b = i(t);
return arc(b);
};
}
function removePieTween(d, i) {
s0 = 2 * Math.PI;
e0 = 2 * Math.PI;
var i = d3.interpolate({startAngle: d.startAngle, endAngle: d.endAngle}, {startAngle: s0, endAngle: e0});
return function(t) {
var b = i(t);
return arc(b);
};
}
function textTween(d, i) {
var a;
if(oldPieData[i]){
a = (oldPieData[i].startAngle + oldPieData[i].endAngle - Math.PI)/2;
} else if (!(oldPieData[i]) && oldPieData[i-1]) {
a = (oldPieData[i-1].startAngle + oldPieData[i-1].endAngle - Math.PI)/2;
} else if(!(oldPieData[i-1]) && oldPieData.length > 0) {
a = (oldPieData[oldPieData.length-1].startAngle + oldPieData[oldPieData.length-1].endAngle - Math.PI)/2;
} else {
a = 0;
}
var b = (d.startAngle + d.endAngle - Math.PI)/2;
var fn = d3.interpolateNumber(a, b);
return function(t) {
var val = fn(t);
return "translate(" + Math.cos(val) * (r+textOffset) + "," + Math.sin(val) * (r+textOffset) + ")";
};
}
$( "#slider" ).slider({
value: 0,
min: 0,
max: 3,
step: 1,
slide: function( event, ui ) {
update(ui.value);
console.log(ui.value);
}
})
.each(function() {
//
// Add labels to slider whose values
// are specified by min, max and whose
// step is set to 1
//
// Get the options for this slider
var opt = $(this).data().uiSlider.options;
// Get the number of possible values
var vals = opt.max - opt.min;
// Space out values
for (var i = 0; i <= vals; i++) {
var el = $('<label>'+dataStructure[i].label+'</label>').css('left',(i/vals*100)+'%');
$( "#slider" ).append(el);
}
});
update(0);
Here is the Jsfiddle of the diagram i'm using:
jsfiddle.net/brusasu/AqP73/
I created two html page, each for the diagrams with the value i need to show.
My question is how to edit the code in a way where i can use the two diagrams in the same html page.
Thanks in advance
Oki Doki. I'm no expert in these things, but looking at the css in your jsfiddle, it appears to be missing the styles that you might want for the divs "slidercontainer2", "pie-chart2 and "slider2".
Make sure that you have these properly duplicated and that will at least get you closer.
Im trying to drawing line Shape (fabric.Line).
and then after drawn shape. it filled image.
When finished drawing an shape, I want to drag an filled image (inside Shape)
Here is the jsfiddle >> http://jsfiddle.net/dTpVw/
var canvas = new fabric.Canvas('c', { selection:false });
var mode = "add";
var currentShape;
canvas.observe("mouse:move", function (event) {
var pos = canvas.getPointer(event.e);
if (mode === "edit" && currentShape) {
if (currentShape.type === "line") {
currentShape.set({
x2 : pos.x,
y2 : pos.y
});
canvas.renderAll();
} else if (currentShape.type === "polygon") {
var points = currentShape.get("points");
points[points.length - 1].x = pos.x - currentShape.get("left");
points[points.length - 1].y = pos.y - currentShape.get("top");
currentShape.set({
points : points
});
canvas.renderAll();
}
}
});
canvas.observe("mouse:down", function (event) {
var pos = canvas.getPointer(event.e);
if (mode === "add") {
var polygon = new fabric.Line([ pos.x, pos.y, pos.x + 2,
pos.y + 2 ], {
fill : 'red'
});
currentShape = polygon;
canvas.add(currentShape);
mode = "edit";
} else if (mode === "edit" && currentShape
&& currentShape.type === "line") {
// replace line with polygon
canvas.remove(currentShape);
var points = [];
points.push({
x : currentShape.x1 - pos.x,
y : currentShape.y1 - pos.y
});
points.push({
x : currentShape.x2 - pos.x,
y : currentShape.y2 - pos.y
});
points.push({
x : currentShape.x2 - pos.x + 5,
y : currentShape.y2 - pos.y + 5
});
var polygon = new fabric.Polygon(points, {
fill : 'blue',
left : pos.x,
top : pos.y,
opacity: 0.5 // 투명도 적용
});
canvas.add(polygon);
Spolygon = polygon;
currentShape = polygon;
canvas.renderAll();
} else if (mode === "edit" && currentShape
&& currentShape.type === "polygon") {
var points = currentShape.get("points");
points.push({
x : pos.x - currentShape.get("left"),
y : pos.y - currentShape.get("top")
});
currentShape.set({
points : points
});
canvas.renderAll();
}
});
function loadPattern(url) {
fabric.util.loadImage(url, function(img) {
console.log(Spolygon);
Spolygon.fill = new fabric.Pattern({
source : img,
repeat : 'repeat'
});
canvas.renderAll();
});
Spolygon.hasControls = false;
// Spolygon.selectable = false;
Spolygon.hasRotatingPoint = false;
Spolygon.lockMovementX = true;
Spolygon.lockMovementY = true;
}
function dblClickHandler(event)
{
currentShape.setCoords();
mode ="add2";
loadPattern('http://fabricjs.com/assets/retina_wood.png');
};
fabric.util.addListener(fabric.document, 'dblclick', dblClickHandler);
//fabric.util.removeListener(canvas.upperCanvasEl, 'dblclick', dblClickHandler);
Thank you for reading my question... Please someone help me T_T
Try something like this in your dblClickHandler event:
function dblClickHandler(event)
{
currentShape.setCoords();
mode ="add2";
loadPattern('http://fabricjs.com/assets/retina_wood.png');
//alert(currentShape.height);
//alert(currentShape.width);
currentShape.hasControls = true;
currentShape.hasRotatingPoint = true;
currentShape.lockMovementX = false;
currentShape.lockMovementY = false;
canvas.setActiveObject(currentShape);
canvas.renderAll();
};
I have updated your fiddle: http://jsfiddle.net/dTpVw/3/
I hope it helps...
I am new to D3 and working on a force directed graph where the json data is dynamic. I am able to change the force graph upon receiving new data but that happens with a springing effect. The code that creates my force graph is :
<div class="graph"></div>
<script>
var w = 660,
h = 700,
r = 10;
var vis = d3.select(".graph")
.append("svg:svg")
.attr("width", w)
.attr("height", h)
.attr("pointer-events", "all")
.append('svg:g')
.call(d3.behavior.zoom().on("zoom", redraw))
.append('svg:g');
vis.append('svg:rect')
.attr('width', w)
.attr('height', h)
.attr('fill', 'rgba(1,1,1,0)');
function redraw() {
console.log("here", d3.event.translate, d3.event.scale);
vis.attr("transform", "translate(" + d3.event.translate + ")" +
" scale(" + d3.event.scale + ")");
};
var force = d3.layout.force()
.gravity(.05)
.charge(-200)
.linkDistance( 260 )
.size([w, h]);
var svg = d3.select(".text")
.append("svg")
.attr("width", w)
.attr("height", h);
d3.json(graph, function(json) {
var nodeList = json.nodes;
var link = vis.selectAll("line")
.data(json.links)
.enter()
.append("line")
.attr("stroke-opacity", function(d) {
if(d.label == 'is a') {
return '0.8';
} else {
return '0.2';
};
})
.attr("stroke-width", function(d) {
if(d.value !== null) {
return d.value;
} else {
return 2;
};
})
.style("stroke", function(d) {
if(d.color !== null) {
return d.color;
};
})
.on("mouseover", function() {
d3.select(this)
.style("stroke", "#999999")
.attr("stroke-opacity", "1.0");
})
.on("mouseout", function() {
d3.select(this)
.style("stroke", function(d) {
if(d.color !== null) {
return d.color;
};
})
.attr("stroke-opacity", function(d) {
if(d.label == 'is a') {
return '0.8';
} else {
return '0.2';
};
})
});
link.append("title")
.text(function(d) { return d.label } );
var node = vis.selectAll("g.node")
.data(json.nodes)
.enter()
.append("svg:g")
.attr("class","node")
.call(force.drag);
node.append("svg:circle")
.attr("r", function(d) {
if (d.size > 0) {
return 10+(d.size*2);
} else {
return 10;
}
})
.attr("id", function(d) { return "Node;"+d.id; } )
.style("fill", function(d) {
if(d.style == 'filled') {
return d.color;
};
})
.style("stroke", function(d) {
if(d.style !== 'filled') {
return d.color;
};
})
.style("stroke-width", "2")
.on("mouseover", function() {
d3.select(this).style("fill", "#999");
fade(.1);
})
.on("mouseout", function(d) {
if (d.style == 'filled') {
d3.select(this).style("fill",d.color);fade(1);
} else {
d3.select(this).style("stroke",d.color);
d3.select(this).style("fill","black");
}
fade(1);
});
node.append("title")
.text(function(d) { return d.Location; } );
force.nodes(json.nodes)
.links(json.links)
.on("tick", tick)
.alpha(1)
.start();
function tick() {
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
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; });
}
});
</script>
I am able to create a new graph when a new json string is received by recalling the whole function again. This creates a new graph in place of the old. I am unable to update the old graph with the new set of values as the values are received; the nodes in my graph do not change, just the relation among them changes.
I did stumble upon an example (http://bl.ocks.org/1095795) where a new node is deleted and recreated, but the implementation is a bit different.
Any pointers or help will be really appreciated.
Well I could find the solution browsing through, posting it here for anyone needing help on this topic. The idea is to create an object of the graph and playing around with the nodes and links arrays.
The JS code goes as:
var graph;
function myGraph(el) {
// Add and remove elements on the graph object
this.addNode = function (id) {
nodes.push({"id":id});
update();
};
this.removeNode = function (id) {
var i = 0;
var n = findNode(id);
while (i < links.length) {
if ((links[i]['source'] == n)||(links[i]['target'] == n))
{
links.splice(i,1);
}
else i++;
}
nodes.splice(findNodeIndex(id),1);
update();
};
this.removeLink = function (source,target){
for(var i=0;i<links.length;i++)
{
if(links[i].source.id == source && links[i].target.id == target)
{
links.splice(i,1);
break;
}
}
update();
};
this.removeallLinks = function(){
links.splice(0,links.length);
update();
};
this.removeAllNodes = function(){
nodes.splice(0,links.length);
update();
};
this.addLink = function (source, target, value) {
links.push({"source":findNode(source),"target":findNode(target),"value":value});
update();
};
var findNode = function(id) {
for (var i in nodes) {
if (nodes[i]["id"] === id) return nodes[i];};
};
var findNodeIndex = function(id) {
for (var i=0;i<nodes.length;i++) {
if (nodes[i].id==id){
return i;
}
};
};
// set up the D3 visualisation in the specified element
var w = 500,
h = 500;
var vis = d3.select("#svgdiv")
.append("svg:svg")
.attr("width", w)
.attr("height", h)
.attr("id","svg")
.attr("pointer-events", "all")
.attr("viewBox","0 0 "+w+" "+h)
.attr("perserveAspectRatio","xMinYMid")
.append('svg:g');
var force = d3.layout.force();
var nodes = force.nodes(),
links = force.links();
var update = function () {
var link = vis.selectAll("line")
.data(links, function(d) {
return d.source.id + "-" + d.target.id;
});
link.enter().append("line")
.attr("id",function(d){return d.source.id + "-" + d.target.id;})
.attr("class","link");
link.append("title")
.text(function(d){
return d.value;
});
link.exit().remove();
var node = vis.selectAll("g.node")
.data(nodes, function(d) {
return d.id;});
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.call(force.drag);
nodeEnter.append("svg:circle")
.attr("r", 16)
.attr("id",function(d) { return "Node;"+d.id;})
.attr("class","nodeStrokeClass");
nodeEnter.append("svg:text")
.attr("class","textClass")
.text( function(d){return d.id;}) ;
node.exit().remove();
force.on("tick", function() {
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
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; });
});
// Restart the force layout.
force
.gravity(.05)
.distance(50)
.linkDistance( 50 )
.size([w, h])
.start();
};
// Make it all go
update();
}
function drawGraph()
{
graph = new myGraph("#svgdiv");
graph.addNode('A');
graph.addNode('B');
graph.addNode('C');
graph.addLink('A','B','10');
graph.addLink('A','C','8');
graph.addLink('B','C','15');
}
I took Rahuls great example, made some changes, and posted a bl.ock complete with animation over time if anyone is interested in a fully functioning example. Adding/removing links/nodes really should be easier than this, but still pretty cool.
http://bl.ocks.org/ericcoopey/6c602d7cb14b25c179a4
In addition to calling drawGraph() in the ready function, you can also embed the posted code inside an inline <script></script>block.
This is how most of the tutorials on the d3 site handle it.