I am trying to tween the heights of the various arcs in this chart
jsfiddle
http://jsfiddle.net/0ht35rpb/193/
I've seen this example but not sure how to start implementing it.
d3 how to tween inner radius for pie chart
I've seen this sample on various tweening maths. http://andyshora.com/tweening-shapes-paths-d3-js.html
var $this = $("#chart");
var data = [{
"label": "Overall Stress",
"value": 89
},{
"label": "Emotional Stress",
"value": 1
},{
"label": "Behavioural difficulties",
"value": 29
},{
"label": "hyperactivity and concetration",
"value": 89
},{
"label": "Getting along with others",
"value": 19
},{
"label": "Keen and helpful behaviour",
"value": 45
}];
var w = 350;
var h = 350;
function colores_google(n) {
var colores_g = ["#f7b363", "#448875", "#c12f39", "#2b2d39", "#f8dd2f", "#c12fff"];
return colores_g[n % colores_g.length];
}
var arcGenerator = {
radius: 70,
oldData: "",
init: function(el, data, w, h){
var stardata = [
{
"segments": data
}
];
this.el = el;
var clone = $.extend(true, {}, stardata);
this.oldData = this.setData(clone, false);
this.setup(el, this.setData(stardata, true), w, h);
},
update: function(data){
var clone = $.extend(true, {}, data);
this.animate(this.setData(data, true));
this.oldData = this.setData(clone, false);
},
animate: function(data){
var that = this;
var chart = d3.select(this.el);
that.generateArcs(chart, data);
},
setData: function(data, isSorted){
var diameter = 2 * Math.PI * this.radius;
var localData = new Array();
var displacement = 0;
var oldBatchLength = 0;
$.each(data, function(index, value) {
var riseLevels = value.segments;
var riseLevelCount = riseLevels.length;
if(oldBatchLength !=undefined){
displacement+=oldBatchLength;
}
var arcBatchLength = 2*Math.PI;
var arcPartition = arcBatchLength/riseLevelCount;
$.each(riseLevels, function( ri, value ) {
var startAngle = (ri*arcPartition);
var endAngle = ((ri+1)*arcPartition);
if(index!=0){
startAngle+=displacement;
endAngle+=displacement;
}
riseLevels[ri]["startAngle"] = startAngle;
riseLevels[ri]["endAngle"] = endAngle;
});
oldBatchLength = arcBatchLength;
localData.push(riseLevels);
});
var finalArray = new Array();
$.each(localData, function(index, value) {
$.each(localData[index], function(i, v) {
finalArray.push(v);
});
});
return finalArray;
},
generateArcs: function(chart, data){
var that = this;
//_arc paths
//append previous value to it.
$.each(data, function(index, value) {
if(that.oldData[index] != undefined){
data[index]["previousEndAngle"] = that.oldData[index].endAngle;
}
else{
data[index]["previousEndAngle"] = 0;
}
});
var arcpaths = that.arcpaths.selectAll("path")
.data(data);
arcpaths.enter().append("svg:path")
.style("fill", function(d, i){
return colores_google(i);
})
.transition()
.ease(d3.easeElastic)
.duration(750)
.attrTween("d", arcTween);
arcpaths.transition()
.ease(d3.easeElastic)
.style("fill", function(d, i){
return colores_google(i);
})
.duration(750)
.attrTween("d",arcTween);
arcpaths.exit().transition()
.ease(d3.easeBounce)
.duration(750)
.attrTween("d", arcTween)
.remove();
function arcTween(b) {
var prev = JSON.parse(JSON.stringify(b));
prev.endAngle = b.previousEndAngle;
var i = d3.interpolate(prev, b);
return function(t) {
return that.getArc()(i(t));
};
}
//_arc paths
var r = that.radius + 40;
var ir = that.radius - 30;
var legendHeight = this.legendPaddingTop;
var ySpace = 18;
var labelPadding = 3;
//draw labels legends
var labels = that.label_group.selectAll("text.labels")
.data(data);
labels.enter().append("svg:text")
.attr("class", "labels")
.attr("dy", function(d, i) {
legendHeight+=ySpace;
return (ySpace * i) + labelPadding;
})
.attr("text-anchor", function(d) {
return "start";
})
.text(function(d) {
return d.label;
});
labels.exit().remove();
var legend = that.legend_group.selectAll("circle").data(data);
legend.enter().append("svg:circle")
.attr("cx", 100)
.attr("cy", function(d, i) {
return ySpace * i;
})
.attr("r", 7)
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d, i) {
return colores_google(i);
});
legend.exit().remove();
//reset legend height
//console.log("optimum height for legend", legendHeight);
$this.find('.legend').attr("height", legendHeight);
/*
//__labels
var starlabels = that.starlabels.selectAll("text")
.data(data);
starlabels.enter()
.append("text")
.attr("text-anchor", "middle")
starlabels.text(function(d) {
return d.label;
})
.each(function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
d.cx = Math.cos(a) * (ir+((r-ir)/2));
d.cy = Math.sin(a) * (ir+((r-ir)/2));
d.x = d.x || Math.cos(a) * (r + 20);
d.y = d.y || Math.sin(a) * (r + 20);
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;
})
.transition()
.duration(300)
.attr("x", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
return d.x = Math.cos(a) * (r + 20);
})
.attr("y", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
return d.y = Math.sin(a) * (r + 20);
});
starlabels.exit().remove();
//__labels
//__pointers
that.pointers.append("defs").append("marker")
.attr("id", "circ")
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("refX", 3)
.attr("refY", 3)
.append("circle")
.attr("cx", 3)
.attr("cy", 3)
.attr("r", 3)
.style("fill", "#005a70");
var pointers = that.pointers.selectAll("path.pointer")
.data(data);
pointers.enter()
.append("path")
.attr("class", "pointer")
.style("fill", "none")
.style("stroke", "#005a70")
.attr("marker-end", "url(#circ)");
pointers
.transition()
.duration(300)
.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;
}
});
pointers.exit().remove();
//__pointers
*/
},
setup: function(el, data, w, h){
var chart = d3.select(el).append("svg")
.attr("class", "chart")
.attr("width", w)
.attr("height", h)
var arcchart = chart.append("g")
.attr("class", "starchart")
.attr("transform", "translate("+w/4+","+h/2+")");
this.arcpaths = arcchart.append("g")
.attr("class", "arcpaths");
this.starlabels = arcchart.append("g")
.attr("class", "labels");
this.pointers = arcchart.append("g")
.attr("class", "pointer");
var margin = 25;
var padding = 15;
this.legendPaddingTop = 30;
var legend = chart.append("g")
.attr("class", "legend")
.attr("width", w/3)
.attr("height", h - 50)
.attr("transform", "translate(" + (w-20) + "," + (h/4) + ")");
this.label_group = legend.append("g")
.attr("class", "label_group")
.attr("transform", "translate(" + (-(w / 3) + 20) + "," + 0 + ")");
this.legend_group = legend.append("g")
.attr("class", "legend_group")
.attr("transform", "translate(" + (-(w / 3) - 100) + "," + 0 + ")");
var radiusControl = 16;
this.dataset = "big";//more than 2 results
if(data.length <=2){
radiusControl = 65;//make the radius smaller to compromise with there being less results
this.dataset = "small";
}
this.radius = w/4 - radiusControl;
this.generateArcs(chart, data);
},
getArc: function(){
var that = this;
var arc = d3.arc()
.innerRadius(function(d, i){
var threshold = 50;
if(that.dataset == "small"){
threshold = 20;
}
return that.radius-threshold;//negative makes it deeper
})
.outerRadius(function(d){
var maxHeight = 120;
var ratio = (d.value/maxHeight * 100)+that.radius;
return ratio;
})
.startAngle(function(d, i){
return d.startAngle;
})
.endAngle(function(d, i){
return d.endAngle;
});
return arc;
}
}
arcGenerator.init($this[0], data, w, h);
In your attrTween function instead of interpolating angle interpolate the value:
function arcTween(b) {
var prev = JSON.parse(JSON.stringify(b));
prev.endAngle = b.previousEndAngle; <-- incorrect
var i = d3.interpolate(prev, b);
Interpolate outer radius like below
function arcTween(b) {
var prev = JSON.parse(JSON.stringify(b));
prev.value = 0;
var i = d3.interpolate(prev, b);
working code here
Related
I have a sunburst which has following layers of data
world=>continents=>countries=>fuels
NOw I want to include names of elements only until countries and not names of fuels. With my code I can add names of all elements in the dropdown but not sure how to remove names of fuels from the dropdown.
Fiddle: http://jsfiddle.net/8wd2xt9n/14/
Full code:
var width = 960,
height = 700,
radius = Math.min(width, height) / 2;
var b = {
w: 130,
h: 30,
s: 3,
t: 10
};
var x = d3.scale.linear()
.range([0, 2 * Math.PI]);
var y = d3.scale.sqrt()
.range([0, radius]);
var changeArray = [100, 80, 60, 0, -60, -80, -100];
var colorArray = ["#67000d", "#b73e43", "#d5464a", "#f26256", "#fb876e", "#fca78e", "#fcbba1", "#fee0d2", "#fff5f0"];
var svg = d3.select("#diagram").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + (height / 2 + 10) + ")");
var partition = d3.layout.partition()
.value(function (d) {
return d.Total;
});
var arc = d3.svg.arc()
.startAngle(function (d) {
return Math.max(0, Math.min(2 * Math.PI, x(d.x)));
})
.endAngle(function (d) {
return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx)));
})
.innerRadius(function (d) {
return Math.max(0, y(d.y));
})
.outerRadius(function (d) {
return Math.max(0, y(d.y + d.dy));
});
console.log(arc)
function checkIt(error, root) {
initializeBreadcrumbTrail();
//intilaize dropdown
if (error) throw error;
var g = svg.selectAll("g")
.data(partition.nodes(root))
.enter().append("g");
var path = g.append("path")
.attr("d", arc)
.style("fill", function (d) {
var color;
if (d.Total_Change > 100) {
color = colorArray[0]
} else if (d.Total_Change > 0 && d.Total_Change < 100) {
color = colorArray[1]
} else {
color = colorArray[2]
}
d.color = color;
return color
})
.on("click", click)
.on("mouseover", mouseover);
var tooltip = d3.select("body")
.append("div")
.attr("id", "tooltips")
.style("position", "absolute")
.style("background-color", "#fff")
.style("z-index", "10")
.style("visibility", "hidden");
g.on("mouseover", function (d) {
return tooltip.style("visibility", "visible")
.html("<div class=" + "tooltip_container>" + "<h4 class=" + "tooltip_heading>" + d.name.replace(/[_-]/g, " ") + "</h4>" + "<br>" + "<p> Emissions 2013:" + " " + "<br>" + d.Total + " " + "<span>in Million Tons</span></p>" + "<br>" + "<p> Change in Emissions: <span>" + (d.Total_Change / d.Total * 100).toPrecision(3) + "%" + "</span></p>" + "</div>");
})
.on("mousemove", function () {
return tooltip.style("top", (d3.event.pageY - 10) + "px").style("left", (d3.event.pageX + 10) + "px");
})
.on("mouseout", function () {
return tooltip.style("visibility", "hidden");
});
//creating a dropdown
var dropDown = d3.select("#dropdown_container")
.append("select")
.attr("class", "selection")
.attr("name", "country-list");
var nodeArr = partition.nodes(root);
var options = dropDown.selectAll("option")
.data(nodeArr)
.enter()
.append("option");
options.text(function (d) {
var prefix = new Array(d.depth + 1);
var dropdownValues = d.name.replace(/[_-]/g, " ");
return dropdownValues;
}).attr("value", function (d) {
var dropdownValues = d.name;
return dropdownValues;
});
// transition on click
function click(d) {
// fade out all text elements
console.log(d)
path.transition()
.duration(750)
.attrTween("d", arcTween(d))
.each("end", function (e, i) {
// check if the animated element's data e lies within the visible angle span given in d
if (e.x >= d.x && e.x < (d.x + d.dx)) {
// get a selection of the associated text element
var arcText = d3.select(this.parentNode).select("text");
// fade in the text element and recalculate positions
arcText.transition().duration(750)
.attr("opacity", 1)
.attr("transform", function () {
return "rotate(" + computeTextRotation(e) + ")"
})
.attr("x", function (d) {
return y(d.y);
});
}
});
};
d3.select(".selection").on("change", function changePie() {
var value = this.value;
var index = this.selectedIndex;
var dataObj = nodeArr[index];
path[0].forEach(function (p) {
var data = d3.select(p).data(); //get the data from the path
if (data[0].name === value) {
console.log(data)
click(data[0]);//call the click function
}
});
console.log(this.value + " :c " + dataObj["Iron and steel"] + " in " + (dataObj.parent && dataObj.parent.name));
});
};
d3.json("https://gist.githubusercontent.com/heenaI/cbbc5c5f49994f174376/raw/743b3964d1dcc0b005ec2b024414877a36b0bd33/data.json", checkIt);
d3.select(self.frameElement).style("height", height + "px");
// Interpolate the scales!
function arcTween(d) {
var xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]),
yd = d3.interpolate(y.domain(), [d.y, 1]),
yr = d3.interpolate(y.range(), [d.y ? 20 : 0, radius]);
return function (d, i) {
return i ? function (t) {
return arc(d);
} : function (t) {
x.domain(xd(t));
y.domain(yd(t)).range(yr(t));
return arc(d);
};
};
}
function initializeBreadcrumbTrail() {
// Add the svg area.
var trail = d3.select("#sequence").append("svg:svg")
.attr("width", width)
.attr("height", 50)
.attr("id", "trail");
// Add the label at the end, for the percentage.
trail.append("svg:text")
.attr("id", "endlabel")
.style("fill", "#000");
}
function breadcrumbPoints(d, i) {
var points = [];
points.push("0,0");
points.push(b.w + ",0");
points.push(b.w + b.t + "," + (b.h / 2));
points.push(b.w + "," + b.h);
points.push("0," + b.h);
if (i > 0) { // Leftmost breadcrumb; don't include 6th vertex.
points.push(b.t + "," + (b.h / 2));
}
return points.join(" ");
}
// Update the breadcrumb trail to show the current sequence and percentage.
function updateBreadcrumbs(nodeArray) {
// Data join; key function combines name and depth (= position in sequence).
var g = d3.select("#trail")
.selectAll("g")
.data(nodeArray, function (d) {
return d.name.replace(/[_-]/g, " ") + d.Total;
});
// Add breadcrumb and label for entering nodes.
var entering = g.enter().append("svg:g");
entering.append("svg:polygon")
.attr("points", breadcrumbPoints)
.style("fill", "#d3d3d3");
entering.append("svg:text")
.attr("x", (b.w + b.t) / 2)
.attr("y", b.h / 2)
.attr("dy", "0.35em")
.attr("text-anchor", "middle")
.text(function (d) {
return d.name.replace(/[_-]/g, " ");
});
// Set position for entering and updating nodes.
g.attr("transform", function (d, i) {
return "translate(" + i * (b.w + b.s) + ", 0)";
});
// Remove exiting nodes.
g.exit().remove();
// Now move and update the percentage at the end.
d3.select("#trail").select("#endlabel")
.attr("x", (nodeArray.length + 0.5) * (b.w + b.s))
.attr("y", b.h / 2)
.attr("dy", "0.35em")
.attr("text-anchor", "middle");
// Make the breadcrumb trail visible, if it's hidden.
d3.select("#trail")
.style("visibility", "");
}
function getAncestors(node) {
var path = [];
var current = node;
while (current.parent) {
path.unshift(current);
current = current.parent;
}
return path;
}
function mouseover(d) {
var sequenceArray = getAncestors(d);
updateBreadcrumbs(sequenceArray);
}
Code that creates dropdown
/creating a dropdown
var dropDown = d3.select("#dropdown_container")
.append("select")
.attr("class", "selection")
.attr("name", "country-list");
var nodeArr = partition.nodes(root);
var options = dropDown.selectAll("option")
.data(nodeArr)
.enter()
.append("option");
options.text(function (d) {
var prefix = new Array(d.depth + 1);
var dropdownValues = d.name.replace(/[_-]/g, " ");
return dropdownValues;
}).attr("value", function (d) {
var dropdownValues = d.name;
return dropdownValues;
});
Data structure can be viewed here
As you are grabbing the values of the dropdown menu from the nodes of the partition, you have the depth of the nodes at hand when setting up the dropdown, thus you can filter:
var nodeArr = partition.nodes(root);
var options = dropDown.selectAll("option")
.data(nodeArr.filter(function(d){return d.depth < 3;}))
.enter()
.append("option");
I hope that helps!
(see fiddle)
I would just pre-process the data. In the original root structure you know the countries are 2 levels down so:
var countries = [];
root.children.forEach(function (c){
c.children.forEach(function (d){
countries.push(d.name.replace(/[_-]/g, " "));
});
});
And the dropdown becomes:
var options = dropDown.selectAll("option")
.data(countries)
.enter()
.append("option");
options.text(function (d) {
return d;
}).attr("value", function (d) {
return d;
});
Updated fiddle.
I have a sunburst for which I would like to initiate zoom ability via dropdown. That is when a country name is selected from the drop down menu its part in the sunburst zooms exactly like when its clicked.
js fiddle: http://jsfiddle.net/8wd2xt9n/7/
var width = 960,
height = 700,
radius = Math.min(width, height) / 2;
var b = {
w: 130, h: 30, s: 3, t: 10
};
var x = d3.scale.linear()
.range([0, 2 * Math.PI]);
var y = d3.scale.sqrt()
.range([0, radius]);
var changeArray = [100,80,60,0, -60, -80, -100];
var colorArray = ["#67000d", "#b73e43", "#d5464a", "#f26256", "#fb876e", "#fca78e", "#fcbba1", "#fee0d2", "#fff5f0"];
var svg = d3.select("#diagram").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + (height / 2 + 10) + ")");
var partition = d3.layout.partition()
.value(function(d) { return d.Total; });
var arc = d3.svg.arc()
.startAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x))); })
.endAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx))); })
.innerRadius(function(d) { return Math.max(0, y(d.y)); })
.outerRadius(function(d) { return Math.max(0, y(d.y + d.dy)); });
console.log(arc)
function checkIt(error, root){
initializeBreadcrumbTrail();
//intilaize dropdown
if (error) throw error;
var g = svg.selectAll("g")
.data(partition.nodes(root))
.enter().append("g");
var path = g.append("path")
.attr("d", arc)
.style("fill", function(d) { var color;
if(d.Total_Change > 100)
{color = colorArray[0]
}
else if(d.Total_Change > 0 && d.Total_Change < 100)
{color = colorArray[1]
}
else
{
color = colorArray[2]
}
d.color = color;
return color})
.on("click", click)
.on("mouseover", mouseover);
var tooltip = d3.select("body")
.append("div")
.attr("id", "tooltips")
.style("position", "absolute")
.style("background-color", "#fff")
.style("z-index", "10")
.style("visibility", "hidden");
g.on("mouseover", function(d){return tooltip.style("visibility", "visible")
.html("<div class=" + "tooltip_container>"+"<h4 class=" + "tooltip_heading>" +d.name.replace(/[_-]/g, " ") +"</h4>" +"<br>" + "<p> Emissions 2013:" + " " + "<br>" + d.Total + " " +"<span>in Million Tons</span></p>"+ "<br>"+ "<p> Change in Emissions: <span>" + (d.Total_Change/d.Total*100).toPrecision(3) + "%" + "</span></p>"+"</div>" );})
.on("mousemove", function(){return tooltip.style("top",(d3.event.pageY-10)+"px").style("left",(d3.event.pageX+10)+"px");})
.on("mouseout", function(){return tooltip.style("visibility", "hidden");});
//creating a dropdown
var dropDown = d3.select("#dropdown_container")
.append("select")
.attr("class", "selection")
.attr("name", "country-list");
var nodeArr = partition.nodes(root);
var options = dropDown.selectAll("option")
.data(nodeArr)
.enter()
.append("option");
options.text(function (d) {
var prefix = new Array(d.depth + 1);
var dropdownValues = d.name.replace(/[_-]/g, " ");
return dropdownValues;
}).attr("value", function (d) {
var dropdownValues = d.name;
return dropdownValues;
});
// transition on click
function click(d) {
// fade out all text elements
path.transition()
.duration(750)
.attrTween("d", arcTween(d))
.each("end", function(e, i) {
// check if the animated element's data e lies within the visible angle span given in d
if (e.x >= d.x && e.x < (d.x + d.dx)) {
// get a selection of the associated text element
var arcText = d3.select(this.parentNode).select("text");
// fade in the text element and recalculate positions
arcText.transition().duration(750)
.attr("opacity", 1)
.attr("transform", function() { return "rotate(" + computeTextRotation(e) + ")" })
.attr("x", function(d) { return y(d.y); });
}
});
};
d3.select(".selection").on("change", function changePie() {
var value = this.value;
var index = this.selectedIndex;
var dataObj = nodeArr[index];
path[0].forEach(function(p){
var data = d3.select(p).data();//get the data from the path
if (data[0].name === value){
path.transition()
.duration(750)
.attrTween("d", arcTween(d))
.each("end", function(e, i) {
// check if the animated element's data e lies within the visible angle span given in d
if (e.x >= d.x && e.x < (d.x + d.dx)) {
// get a selection of the associated text element
var arcText = d3.select(this.parentNode).select("text");
// fade in the text element and recalculate positions
arcText.transition().duration(750)
.attr("opacity", 1)
.attr("transform", function() { return "rotate(" + computeTextRotation(e) + ")" })
.attr("x", function(d) { return y(d.y); });
}
});
}
});
console.log(this.value + " :c " + dataObj["Iron and steel"] + " in " + (dataObj.parent && dataObj.parent.name));
});
};
d3.json("https://gist.githubusercontent.com/heenaI/cbbc5c5f49994f174376/raw/55c672bbca7991442f1209cfbbb6ded45d5e8c8e/data.json", checkIt);
d3.select(self.frameElement).style("height", height + "px");
// Interpolate the scales!
function arcTween(d) {
var xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]),
yd = d3.interpolate(y.domain(), [d.y, 1]),
yr = d3.interpolate(y.range(), [d.y ? 20 : 0, radius]);
return function(d, i) {
return i
? function(t) { return arc(d); }
: function(t) { x.domain(xd(t)); y.domain(yd(t)).range(yr(t)); return arc(d); };
};
}
function initializeBreadcrumbTrail() {
// Add the svg area.
var trail = d3.select("#sequence").append("svg:svg")
.attr("width", width)
.attr("height", 50)
.attr("id", "trail");
// Add the label at the end, for the percentage.
trail.append("svg:text")
.attr("id", "endlabel")
.style("fill", "#000");
}
function breadcrumbPoints(d, i) {
var points = [];
points.push("0,0");
points.push(b.w + ",0");
points.push(b.w + b.t + "," + (b.h / 2));
points.push(b.w + "," + b.h);
points.push("0," + b.h);
if (i > 0) { // Leftmost breadcrumb; don't include 6th vertex.
points.push(b.t + "," + (b.h / 2));
}
return points.join(" ");
}
// Update the breadcrumb trail to show the current sequence and percentage.
function updateBreadcrumbs(nodeArray) {
// Data join; key function combines name and depth (= position in sequence).
var g = d3.select("#trail")
.selectAll("g")
.data(nodeArray, function(d) { return d.name.replace(/[_-]/g, " ") + d.Total; });
// Add breadcrumb and label for entering nodes.
var entering = g.enter().append("svg:g");
entering.append("svg:polygon")
.attr("points", breadcrumbPoints)
.style("fill", "#d3d3d3");
entering.append("svg:text")
.attr("x", (b.w + b.t) / 2)
.attr("y", b.h / 2)
.attr("dy", "0.35em")
.attr("text-anchor", "middle")
.text(function(d) { return d.name.replace(/[_-]/g, " "); });
// Set position for entering and updating nodes.
g.attr("transform", function(d, i) {
return "translate(" + i * (b.w + b.s) + ", 0)";
});
// Remove exiting nodes.
g.exit().remove();
// Now move and update the percentage at the end.
d3.select("#trail").select("#endlabel")
.attr("x", (nodeArray.length + 0.5) * (b.w + b.s))
.attr("y", b.h / 2)
.attr("dy", "0.35em")
.attr("text-anchor", "middle");
// Make the breadcrumb trail visible, if it's hidden.
d3.select("#trail")
.style("visibility", "");
}
function getAncestors(node) {
var path = [];
var current = node;
while (current.parent) {
path.unshift(current);
current = current.parent;
}
return path;
}
function mouseover(d) {
var sequenceArray = getAncestors(d);
updateBreadcrumbs(sequenceArray);}
Add this one line and it will work :)
Inside your selection change add this var d = data[0]; as shown below:
d3.select(".selection").on("change", function changePie() {
var value = this.value;
var index = this.selectedIndex;
var dataObj = nodeArr[index];
path[0].forEach(function(p){
var data = d3.select(p).data();//get the data from the path
if (data[0].name === value){
var d = data[0];//this line is missing
path.transition()
Working code here
Other option is to call the click function on selection change like below
d3.select(".selection").on("change", function changePie() {
var value = this.value;
var index = this.selectedIndex;
var dataObj = nodeArr[index];
path[0].forEach(function (p) {
var data = d3.select(p).data(); //get the data from the path
if (data[0].name === value) {
console.log(data)
click(data[0]);//call the click function
}
Working code here
Hope this helps!
I'm developing a legend toggling d3.js pie chart application using this jsfiddle as my latest version http://jsfiddle.net/Qh9X5/3328/ .
I am aiming to get a streamlined working example where the legend can toggle the slices, trying to deactivate all slices - resorts in a reset which reactivates all the slices. Splitting up presentation and application layer logic.
Tweening needs improvement too - as the slices pop into existence then re-tween smoothly.
How do I improve/fix the various bugs in this code base?
onLegendClick: function(dt, i){
//_toggle rectangle in legend
var completeData = jQuery.extend(true, [], methods.currentDataSet);
newDataSet = completeData;
if(methods.manipulatedData){
newDataSet = methods.manipulatedData;
}
d3.selectAll('rect')
.data([dt], function(d) {
return d.data.label;
})
.style("fill-opacity", function(d, j) {
var isActive = Math.abs(1-d3.select(this).style("fill-opacity"));
if(isActive){
newDataSet[j].total = completeData[j].total;
}else{
newDataSet[j].total = 0;
}
return isActive;
});
//animate slices
methods.animateSlices(newDataSet);
//stash manipulated data
methods.manipulatedData = newDataSet;
}
Here is the entire js code - I've used the tidyup. I wasn't sure about using the shortcuts as I'm not sure the values will be correct. The latest fiddle - http://jsfiddle.net/Qh9X5/3340/
$(document).ready(function () {
var pieChart = {
el: "",
init: function (el, options) {
var clone = jQuery.extend(true, {}, options["data"]);
pieChart.el = el;
pieChart.setup(clone, options["width"], options["height"], options["r"], options["ir"]);
},
getArc: function (radius, innerradius) {
var arc = d3.svg.arc()
.innerRadius(innerradius)
.outerRadius(radius);
return arc;
},
setup: function (dataset, w, h, r, ir) {
var padding = 80;
this.width = w;
this.height = h;
this.radius = r
this.innerradius = ir;
this.color = d3.scale.category20();
this.pie = d3.layout.pie()
.sort(null)
.value(function (d) {
return d.total;
});
this.arc = this.getArc(this.radius, this.innerradius);
this.svg = d3.select(pieChart.el["selector"]).append("svg")
.attr("width", this.width + padding)
.attr("height", this.height + padding);
this.holder = this.svg.append("g")
.attr("transform", "translate(" + ((this.width / 2) + (padding / 2)) + "," + ((this.height / 2) + (padding / 2)) + ")");
this.piec = this.holder.append("g")
.attr("class", "piechart");
this.segments = this.holder.append("g")
.attr("class", "segments");
this.labels = this.holder.append("g")
.attr("class", "labels");
this.pointers = this.holder.append("g")
.attr("class", "pointers");
this.legend = this.svg.append("g")
.attr("class", "legend")
.attr("transform", "translate(" + -(this.width / 4) + "," + this.height + ")");
},
oldPieData: "",
pieTween: function (r, ir, d, i) {
var that = this;
var theOldDataInPie = pieChart.oldPieData;
// Interpolate the arcs in data space
var s0;
var e0;
if (theOldDataInPie[i]) {
s0 = theOldDataInPie[i].startAngle;
e0 = theOldDataInPie[i].endAngle;
} else if (!(theOldDataInPie[i]) && theOldDataInPie[i - 1]) {
s0 = theOldDataInPie[i - 1].endAngle;
e0 = theOldDataInPie[i - 1].endAngle;
} else if (!(theOldDataInPie[i - 1]) && theOldDataInPie.length > 0) {
s0 = theOldDataInPie[theOldDataInPie.length - 1].endAngle;
e0 = theOldDataInPie[theOldDataInPie.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 pieChart.getArc(r, ir)(b);
};
},
removePieTween: function (r, ir, d, i) {
var that = this;
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 pieChart.getArc(r, ir)(b);
};
},
animateSlices: function (dataSet) {
var r = $(pieChart.el["selector"]).data("r");
var ir = $(pieChart.el["selector"]).data("ir");
this.piedata = pieChart.pie(dataSet);
//__slices
this.path = pieChart.segments.selectAll("path.pie")
.data(this.piedata, function (d) {
return d.data.label
});
this.path.enter().append("path")
.attr("class", "pie")
.attr("fill", function (d, i) {
return pieChart.color(i);
})
.attr("stroke", "#ffffff")
.transition()
.duration(300)
.attrTween("d", function (d, i) {
return pieChart.pieTween(r, ir, d, i);
});
this.path.transition()
.duration(300)
.attrTween("d", function (d, i) {
return pieChart.pieTween(r, ir, d, i);
});
this.path.exit()
.transition()
.duration(300)
.attrTween("d", function (d, i) {
return pieChart.removePieTween(r, ir, d, i);
})
.remove();
//__slices
//__labels
var labels = pieChart.labels.selectAll("text")
.data(this.piedata, function (d) {
return d.data.label
});
labels.enter()
.append("text")
.attr("text-anchor", "middle")
labels.attr("x", function (d) {
var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
d.cx = Math.cos(a) * (ir + ((r - ir) / 2));
return d.x = Math.cos(a) * (r + 20);
})
.attr("y", function (d) {
var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
d.cy = Math.sin(a) * (ir + ((r - ir) / 2));
return d.y = Math.sin(a) * (r + 20);
})
.attr("opacity", function (d) {
var opacityLevel = 1;
if (d.value == 0) {
opacityLevel = 0;
}
return opacityLevel;
})
.text(function (d) {
return d.data.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;
})
.transition()
.duration(300)
labels.transition()
.duration(300)
labels.exit().remove();
//__labels
//__pointers
pieChart.pointers.append("defs").append("marker")
.attr("id", "circ")
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("refX", 3)
.attr("refY", 3)
.append("circle")
.attr("cx", 3)
.attr("cy", 3)
.attr("r", 3);
var pointers = pieChart.pointers.selectAll("path.pointer")
.data(this.piedata, function (d) {
return d.data.label
});
pointers.enter()
.append("path")
.attr("class", "pointer")
.style("fill", "none")
.style("stroke", "black")
.attr("marker-end", "url(#circ)");
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;
}
})
.attr("opacity", function (d) {
var opacityLevel = 1;
if (d.value == 0) {
opacityLevel = 0;
}
return opacityLevel;
})
.transition()
.duration(300)
pointers.transition()
.duration(300)
pointers.exit().remove();
},
onToggle: function (sliceData, index) {
//_toggle rectangle in legend
//_toggle slice
var completeData = jQuery.extend(true, [], pieChart.currentDataSet);
var dataLength = completeData.length;
var newDataSet = completeData;
if (pieChart.manipulatedData) {
newDataSet = pieChart.manipulatedData;
}
d3.selectAll('rect')
.data([sliceData], function (d) {
return d.data.label;
})
.style("fill-opacity", function (d) {
var isActive = Math.abs(1 - d3.select(this).style("fill-opacity"));
if (isActive) {
newDataSet[index].total = completeData[index].total;
newDataSet[index].value = completeData[index].value;
} else {
newDataSet[index].total = 0;
newDataSet[index].value = 0;
}
return isActive;
});
//if all elements are to be not shown - reset to show all slices again.
//animate slices
pieChart.animateSlices(newDataSet);
//stash manipulated data
pieChart.manipulatedData = newDataSet;
},
update: function (el, dataSet) {
var that = this;
pieChart.el = el;
pieChart.svg = d3.select(pieChart.el["selector"] + " .piechart");
pieChart.segments = d3.select(pieChart.el["selector"] + " .segments");
pieChart.labels = d3.select(pieChart.el["selector"] + " .labels");
pieChart.pointers = d3.select(pieChart.el["selector"] + " .pointers");
pieChart.legend = d3.select(pieChart.el["selector"] + " .legend");
dataSet.forEach(function (d) {
d.total = +d.value;
});
pieChart.currentDataSet = dataSet;
pieChart.animateSlices(dataSet);
//__legends
var w = 200;
// add legend
var legend = pieChart.legend; //.append("g")
var legendRects = legend.selectAll('rect')
.data(this.piedata, function (d) {
return d.data.label
});
legendRects.enter()
.append("rect")
.attr("x", w - 65)
.attr("y", function (d, i) {
return i * 20;
})
.attr("width", 10)
.attr("height", 10)
.style("fill", function (d, i) {
return pieChart.color(i);
})
.style("stroke", function (d, i) {
return pieChart.color(i);
})
.on('click', function(d, i){
pieChart.onToggle(d, i);
})
.transition()
.duration(300)
legendRects.style("fill", function (d, i) {
return pieChart.color(i);
})
.style("stroke", function (d, i) {
return pieChart.color(i);
})
.transition()
.duration(300)
legendRects.exit().remove();
var legendText = legend.selectAll('text.label')
.data(this.piedata, function (d) {
return d.data.label
});
legendText.enter()
.append("text")
.attr("class", "label")
.attr("x", w - 52)
.attr("y", function (d, i) {
return i * 20 + 9;
})
.text(function (d) {
return d.data.label;
})
.transition()
.duration(300)
legendText.text(function (d) {
return d.data.label;
})
.transition()
.duration(300)
legendText.exit().remove();
var legendTextVals = legend.selectAll('text.vals')
.data(this.piedata, function (d) {
return d.data.label
});
legendTextVals.enter()
.append("text")
.attr("class", "vals")
.attr("x", w + 20)
.attr("y", function (d, i) {
return i * 20 + 9;
})
.text(function (d) {
return d.data.value;
})
.transition()
.duration(300)
legendTextVals.text(function (d) {
return d.data.value;
})
.transition()
.duration(300)
legendTextVals.exit().remove();
//__pointers
this.oldPieData = this.piedata;
}
};
var dataCharts = [{
"data": [{
"segments": [{
"label": "apple",
"value": 53245
}, {
"label": "cherry",
"value": 145
}, {
"label": "pear",
"value": 2245
}, {
"label": "bananana",
"value": 15325
}]
}]
}, {
"data": [{
"segments": [{
"label": "milk",
"value": 122
}, {
"label": "cheese",
"value": 44
}, {
"label": "grapes",
"value": 533
}]
}]
}, {
"data": [{
"segments": [{
"label": "pineapple",
"value": 1532
}, {
"label": "orange",
"value": 1435
}, {
"label": "grapes",
"value": 22
}]
}]
}, {
"data": [{
"segments": [{
"label": "lemons",
"value": 133
}, {
"label": "mango",
"value": 435
}, {
"label": "melon",
"value": 2122
}]
}]
}];
var clone = jQuery.extend(true, {}, dataCharts);
//__invoke concentric
$('[data-role="piechart"]').each(function (index) {
var selector = "piechart" + index;
$(this).attr("id", selector);
var options = {
data: clone[0].data,
width: $(this).data("width"),
height: $(this).data("height"),
r: $(this).data("r"),
ir: $(this).data("ir")
}
pieChart.init($("#" + selector), options);
pieChart.update($("#" + selector), clone[0].data[0].segments);
});
$(".testers a").on("click", function (e) {
e.preventDefault();
var clone = jQuery.extend(true, {}, dataCharts);
var min = 0;
var max = 3;
//__invoke pie chart
$('[data-role="piechart"]').each(function (index) {
pos = Math.floor(Math.random() * (max - min + 1)) + min;
pieChart.update($("#" + $(this).attr("id")), clone[pos].data[0].segments);
});
});
});
Can anybody help me convert the d3.js Calendar View implementation which looks like the one depicted here (weeks as columns): D3 Calendar View using Associative Array
to something more like this (weeks as rows): http://kamisama.github.io/cal-heatmap/v2/ (See Months > days (horizontally) section)
I've had a go at playing around with the axes, but to no avail.
Any help would be greatly appreciated.
My current code looks like this:
raApp.directive('heatMapYear', function () {
var width = 1200,
height = 150,
cellSize = 17; // cell size
var day = d3.time.format("%w"),
week = d3.time.format("%U"),
month = d3.time.format("%m"),
monthName = d3.time.format("%b"),
format = d3.time.format("%Y-%m-%d");
var color = d3.scale.quantize()
.domain([1, 5])
.range(d3.range(5).map(function(d) { return "rank" + d; }));
return {
restrict: 'A'
, replace: false
, scope: {
chartData: '='
, dateField: '='
}
, link: function (scope, element, attrs) {
scope.$watch('chartData', function(newData, oldData) {
d3.select(element[0]).selectAll('*').remove();
if (newData != undefined) {
var svg = d3.select(element[0]).selectAll("svg")
.data(function() {
var years = [];
for (var i = 0; i < newData.length; i++) {
var date = newData[i][scope.dateField];
var year = parseInt(date.substring(0, 4));
if (years.indexOf(year) == -1) {
years.push(year);
}
}
return years;
})
.enter().append("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "heatClass")
.append("g")
.attr("transform", "translate(" + 50 + "," + (height - cellSize * 7 - 1) + ")");
svg.append("text")
.attr("transform", "translate(-30," + cellSize * 3.5 + ")rotate(-90)")
.style("text-anchor", "middle")
.style("font-weight", "bold")
.text(function(d) { return d; });
svg.selectAll(".monthName")
.data(function(d) { return d3.time.months(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("text")
.attr("x", function(d) {return (week(d) * cellSize + 50); })
.attr("y", -5)
.style("text-anchor", "middle")
.text(function(d) { return monthName(d); });
svg.selectAll(".dayName")
.data(function(d) { return ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"] })
.enter().append("text")
.attr("x", -10)
.attr("y", function(d, i) {return (i * cellSize) + 12; })
.style("text-anchor", "middle")
.text(function(d) { return d; });
var svg1 = d3.select(element[0]).select("svg")
var legend = svg1.selectAll(".legend")
.data([0])
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {
return "translate(130," + (i * (cellSize) + 30) + ")";
});
legend.append("svg:image")
.attr("xlink:href", "img/RA-scale-small.png")
.attr("x", width - 350)
.attr("y", 0)
.attr("width",200)
.attr("height", 47);
var rect = svg.selectAll(".day")
.data(function(d) { return d3.time.days(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("rect")
.attr("class", "day")
.attr("width", cellSize)
.attr("height", cellSize)
.attr("x", function(d) { return week(d) * cellSize; })
.attr("y", function(d) { return day(d) * cellSize; })
.datum(format);
rect.append("title")
.text(function(d) { return d; });
svg.selectAll(".month")
.data(function(d) { return d3.time.months(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("path")
.attr("class", "month")
.attr("d", monthPath);
var data = d3.nest()
.key(function(d) { return d[scope.dateField]; })
.rollup(function(d) {return {rank:d[0]["rank"],revenue:d[0]["abbrRevenue"],volume:d[0]["abbrVolume"]}})
.map(newData);
rect.filter(function(d) { return d in data; })
.attr("class", function(d) {return "day " + color(data[d].rank); })
.select("title")
.text(function(d) { return d + "\nRevenue: " + data[d].revenue + "\nVolume: " + data[d].volume });
}
});
function monthPath(t0) {
var t1 = new Date(t0.getFullYear(), t0.getMonth() + 1, 0),
d0 = +day(t0), w0 = +week(t0),
d1 = +day(t1), w1 = +week(t1);
return "M" + (w0 + 1) * cellSize + "," + d0 * cellSize
+ "H" + w0 * cellSize + "V" + 7 * cellSize
+ "H" + w1 * cellSize + "V" + (d1 + 1) * cellSize
+ "H" + (w1 + 1) * cellSize + "V" + 0
+ "H" + (w0 + 1) * cellSize + "Z";
}
}
}
});
After much digging around and trial and error, I figured out a solution to this. Therefore I wanted to share the code in case it helps anyone else out there looking to achieve similar results.
The code is as follows:
raApp.directive('heatMapYearWeekRows', function () {
var width = 1490,
height = 200,
cellSize = 17; // cell size
var day = d3.time.format("%w"),
week = d3.time.format("%U"),
month = d3.time.format("%m"),
monthName = d3.time.format("%b"),
format = d3.time.format("%Y-%m-%d"),
displayFormat = d3.time.format("%a, %d %b %Y");
var color = d3.scale.quantize()
.domain([1, 5])
.range(d3.range(5).map(function(d) { return "rank" + d; }));
return {
restrict: 'A'
, replace: false
, scope: {
chartData: '='
, dateField: '='
}
, link: function (scope, element, attrs) {
scope.$watch('chartData', function(newData, oldData) {
d3.select(element[0]).selectAll('*').remove();
if (newData != undefined) {
var svg = d3.select(element[0]).selectAll("svg")
.data(function() {
var years = [];
for (var i = 0; i < newData.length; i++) {
var date = newData[i][scope.dateField];
var year = parseInt(date.substring(0, 4));
if (years.indexOf(year) == -1) {
years.push(year);
}
}
return years;
})
.enter().append("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "heatClass")
.append("g")
.attr("transform", "translate(" + 50 + "," + (height - cellSize * 7 - 1) + ")");
svg.append("text")
.attr("transform", "translate(-30," + cellSize * 3.5 + ")rotate(-90)")
.style("text-anchor", "middle")
.style("font-weight", "bold")
.text(function(d) { return d; });
svg.selectAll(".monthName")
.data(function(d) { return d3.time.months(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("text")
.attr("x", function(d) {
return ((month(d) - 1) * (7 * cellSize) + 50);
})
.attr("y", 115)
.style("text-anchor", "middle")
.style("font-weight", "bold")
.text(function(d) { return monthName(d); });
var svg1 = d3.select(element[0]).select("svg")
var legend = svg1.selectAll(".legend")
.data([0])
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {
return "translate(130," + (i * (cellSize) + 30) + ")";
});
legend.append("svg:image")
.attr("xlink:href", "img/RA-scale-small.png")
.attr("x", -80)
.attr("y", -30)
.attr("width",200)
.attr("height", 47);
var rect = svg.selectAll(".day")
.data(function(d) { return d3.time.days(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("rect")
.attr("class", "day")
.attr("width", cellSize)
.attr("height", cellSize)
.attr("x", function(d) {
var prevDay = new Date(d -1);
var monthOffset = (month(d) - 1) * (7 * cellSize);
var result = (day(d) * cellSize) + +monthOffset;
return result; })
.attr("y", function(d) {
var result = ((getMonthWeek(d) - 1) * cellSize);
return result; })
.datum(format);
rect.append("title")
.text(function(d) {
return d;
});
svg.selectAll(".month")
.data(function(d) { return d3.time.months(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("path")
.attr("class", "month")
.attr("d", monthPath);
var data = d3.nest()
.key(function(d) { return d[scope.dateField]; })
.rollup(function(d) {return {rank:d[0]["rank"],revenue:d[0]["abbrRevenue"],volume:d[0]["abbrVolume"]}})
.map(newData);
rect.filter(function(d) { return d in data; })
.attr("class", function(d) {return "day " + color(data[d].rank); })
.select("title")
.text(function(d) { return displayFormat(new Date(d)) + "\nRevenue: " + data[d].revenue + "\nVolume: " + data[d].volume });
}
});
function getMonthWeek(date){
var firstDay = new Date(date.getFullYear(), date.getMonth(), 1).getDay();
return Math.ceil((date.getDate() + firstDay)/7);
}
function monthPath(t0) {
var t1 = new Date(t0.getFullYear(), t0.getMonth() + 1, 0),
d0 = +day(t0), w0 = +getMonthWeek(t0) -1, m0 = +month(t0),
d1 = +day(t1), w1 = +getMonthWeek(t1) -1;
var monthOffsetX = (+m0 - 1) * (7 * cellSize);
return "M" + ((d0 * cellSize) + +monthOffsetX) + "," + ((w0 + 1) * cellSize)
+ "V" + w0 * cellSize + "H" + ((7 * cellSize) + +monthOffsetX)
+ "V" + w1 * cellSize + "H" + (((d1 + 1) * cellSize) + +monthOffsetX)
+ "V" + ((w1 + 1) * cellSize) + "H" + +monthOffsetX
+ "V" + ((w0 + 1) * cellSize) + "Z";
}
}
}
});
Hope that helps.
I am trying to render an tree diagram using d3.js (which I am very new at). So I am not sure how to make the bottom-to top orientation. I used as reference the example here.
I also want that for every node click node attributes will be displayed (click function call).
Can somebody enlighten me with this? Thanks
Here's my code so far.
var orientation = {
"": {
size: [width, height],
x: function(node) { return node.x; },
y: function(node) { return height - node.y; }
},
};
var data = (function () {
var jason = null;
$.ajax({
'async': false,
'global': false,
'url': "/../GMGR_restructure/json/tree6.json",
'dataType': "json",
'success': function (data) {
jason = data;
}
});
return jason;
})();
var realWidth = window.innerWidth;
var realHeight = window.innerHeight;
var margin = {top: 140, right: 10, bottom: 140, left: 10},
m = [0, 1000, 0, 100],
width = 1500 - margin.left - margin.right,
height = 1000 - margin.top - margin.bottom
h = realHeight -m[0] -m[2],
rectW = 200;
rectH = 30;
w = realWidth -m[0] -m[0];
var customNodes = new Array(),
tmpNodes,
label_w = 70,
branch_w = 70,
layer_wider_label = new Array(),
depencencyChart;
function graph2() {
var ms = document.getElementById('maxStep').value;
tmpNodes = d3.layout.tree().size([600, 1000]).nodes(data);//.on("click", click);
//Create a svg canvas
depencencyChart = d3.select("#graphDiv").append("svg:svg")
.data(d3.entries(orientation))
.attr("width", 2000)
.attr("height", 1000)
.append("svg:g")
.attr("class","drawarea")
.attr("transform", "translate(80, 80)") // shift everything to the right
//.on("click", click);
var fakeTxtBox = depencencyChart.append("svg:text")
.attr("id", "fakeTXT")
.attr("text-anchor", "right")
.text(data.name + "(" + data.gid + ")");
//.on("click", click);
layer_wider_label[0] = fakeTxtBox.node().getComputedTextLength();
depencencyChart.select("#fakeTXT").remove();
data.y = getNodeY(data.id);
data.x = 0;
data.depth = parseInt(data.layer);
customNodes.push(data);//.on("click", click);
prepareNodes(data.children);//.on("click", click(data));
//align nodes.
updateNodesXOffset()
if(ms==""||ms==" "||ms=="All")
drawChart2();
else
drawChart(ms);
d3.select("g")
.call(d3.behavior.zoom()
.scaleExtent([0.1,5])
.on("zoom", zoom));
}
function updateNodesXOffset(){
var x_offsets = new Array();
x_offsets[0] = 0;
customNodes.forEach(function(node) {
node.x = 0;
if (node.layer > 0) {
node.x = x_offsets[node.layer - 1] + layer_wider_label[node.layer - 1] + branch_w;
x_offsets[node.layer] = node.x;
}
});
}
function getNodeY(id) {
var ret = 0;
tmpNodes.some(function(node) {
if (node.id === id) {
//return x:d3.tree has a vertical layout by default.
ret = node.x;
return;
}
})
return ret;
}
function prepareNodes(nodes) {
nodes.forEach(function(node) {
prepareNode(node);
if (node.children) {
prepareNodes(node.children);
}
});
}
function prepareNode(node) {
node.y = getNodeY(node.id);
//.on("click", click);
//fake element to calculate labels area width.
var fakeTxtBox = depencencyChart.append("svg:text")
.attr("id", "fakeTXT")
.attr("text-anchor", "right")
.text(node.name + " : " + node.gid)
//.on("click", click(node));
var this_label_w = fakeTxtBox.node().getComputedTextLength();
depencencyChart.select("#fakeTXT").remove();
if (layer_wider_label[node.layer] == null) {
layer_wider_label[node.layer] = this_label_w;
} else {
if (this_label_w > layer_wider_label[node.layer]) {
layer_wider_label[node.layer] = this_label_w;
}
}
//x will be set
node.depth = parseInt(node.layer);
customNodes.push(node);
//node.on("click", click(node));
}
function customSpline(d) {
var p = new Array();
p[0] = d.source.x + "," + d.source.y;
p[3] = d.target.x + "," + d.target.y;
var m = (d.source.x + d.target.x) / 2
p[1] = m + "," + d.source.y;
p[2] = m + "," + d.target.y;
//This is to change the points where the spline is anchored
//from [source.right,target.left] to [source.top,target.bottom]
// var m = (d.source.y + d.target.y)/2
// p[1] = d.source.x + "," + m;
// p[2] = d.target.x + "," + m;
return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3];
}
function drawChart(ms) {
var cnt=0;
customNodes.forEach(function(node) { //alert(node.layer);
if(node.depth <= ms){
cnt++;
var nodeSVG = depencencyChart.append("svg:g")
.attr("transform", "translate(" + node.x + "," + node.y + ")")
//alert(node.depth);
if (node.depth > 0) {
nodeSVG.append("svg:circle")
.attr("stroke", node.children ? "#3191c1" : "#269926")
.attr("fill", "#fff")
.attr("r", 3)
}
var txtBox = nodeSVG.append("svg:text")
.on("click", click)
.attr("class", "name")
.attr("dx", 8)
.attr("dy", 4)
//.attr("fill", node.current ? "#ffffff" : node.children ? "#226586" : "#269926")
.attr("fill", node.current ? "#ffffff" : node.children ? "#ffffff" : "#ffffff")
.text(node.name)
//.text(node.name + " \n (" + node.gid + ") ")
//.attr("dx", 8)
//.attr("dy", 8)
//.text(node.gid)
var txtW = txtBox.node().getComputedTextLength();
nodeSVG.insert("rect", "text")
.attr("fill", node.children ? "#3191c1" : "#3191c1")
.attr("stroke", "black")
.attr("width", txtW + 8)
.attr("height", "20")
.attr("y", "-12")
.attr("x", "5")
.attr("rx", 4)
.attr("ry", 4)
//.on("click", click(node))
if (node.current) {
nodeSVG.insert("rect", "text")
.attr("fill", node.children ? "#FF4D4D" : "#269926")
.attr("width", txtW + 8)
.attr("height", "20")
.attr("y", "-12")
.attr("x", "5")
.attr("rx", 4)
.attr("ry", 4)
}
//if(cnt <= ms){
if (node.children) {
node.x = node.x + txtW + 20;
//prepare links;
var links = new Array();
node.children.forEach(function(child) {
var st = new Object();
st.source = node;
// st.parent = node;
st.target = child;
st.warning = child.warning;
links.push(st);
})
//.on("click", click(node));
//draw links (under nodes)
depencencyChart.selectAll("pathlink")
.data(links)
.enter().insert("svg:path", "g")
.attr("class", function(d) {
return d.warning === "true" ? "link warning" : "link"
})
.attr("d", customSpline)
//draw a node at the end of the link
nodeSVG.append("svg:circle")
.attr("stroke", "#3191c1")
.attr("fill", "#fff")
.attr("r", 5.5)
//.on("click", click(node))
.attr("transform", "translate(" + (txtW + 20) + ",0)");
//}
}
//node.on("click", click(node));
}
});
d3.select("svg")
.call(d3.behavior.zoom()
.scaleExtent([0.5, 10])
.on("zoom", zoom));
//update(data);
}
function drawChart2() {
var cnt=0;
customNodes.forEach(function(node) {
//if(node.depth <= ms){
cnt++;
var nodeSVG = depencencyChart.append("svg:g")
.attr("transform", "translate(" + node.x + "," + node.y + ")")
//alert(node.depth);
if (node.depth > 0) {
nodeSVG.append("svg:circle")
.attr("stroke", node.children ? "#3191c1" : "#269926")
.attr("fill", "#fff")
.attr("r", 3)
//.attr("x",(node.x-5))
//.attr("y",(node.y-8))
}
var txtBox = nodeSVG.append("svg:text")
//.on("click", click(node))
.attr("class", "name")
.attr("dx", 8)
.attr("dy", 4)
//.attr("fill", node.current ? "#ffffff" : node.children ? "#226586" : "#269926")
.attr("fill", node.current ? "#ffffff" : node.children ? "#ffffff" : "#ffffff")
.text(node.name)
/*.html(function(node){
var str=node.name;
if(str.length>10){
var txt1=str.slice(0,10);
txt1+="<br/>";
txt2=str.slice(10,str.length);
return txt1+txt2;
}
return node.name;
});*/
//.text(node.name + " \n (" + node.gid + ") ")
//.attr("dx", 8)
//.attr("dy", 8)
//.text(node.gid)
var txtW = txtBox.node().getComputedTextLength();
nodeSVG.insert("rect", "text")
.attr("fill", node.children ? "#3191c1" : "#3191c1")
.attr("stroke", "black")
.attr("width", txtW + 8)
.attr("height", "20")
.attr("y", "-12")
.attr("x", "5")
.attr("rx", 4)
.attr("ry", 4)
//.on("click", click(node))
if (node.current) {
nodeSVG.insert("rect", "text")
.attr("fill", node.children ? "#FF4D4D" : "#269926")
.attr("width", txtW + 8)
.attr("height", "20")
.attr("y", "-12")
.attr("x", "5")
.attr("rx", 4)
.attr("ry", 4)
}
//if(cnt <= ms){
if (node.children) {
node.x = node.x + txtW + 20;
//prepare links;
var links = new Array();
node.children.forEach(function(child) {
var st = new Object();
st.source = node;
// st.parent = node;
st.target = child;
st.warning = child.warning;
links.push(st);
})
//.on("click", click(node));
//draw links (under nodes)
depencencyChart.selectAll("pathlink")
.data(links)
.enter().insert("svg:path", "g")
.attr("class", function(d) {
return d.warning === "true" ? "link warning" : "link"
})
.attr("d", customSpline)
//draw a node at the end of the link
nodeSVG.append("svg:circle")
.attr("stroke", "#3191c1")
.attr("fill", "#fff")
.attr("r", 5.5)
//.on("click", click(node))
.attr("transform", "translate(" + (txtW + 20) + ",0)");
//}
}
//node.on("click", click(node));
//}
});
d3.select("svg")
.call(d3.behavior.zoom()
.scaleExtent([0.5, 10])
.on("zoom", zoom));
//update(data);
}
function zoom() {
var scale = d3.event.scale,
translation = d3.event.translate,
tbound = -h * scale,
bbound = h * scale,
lbound = (-w - m[1]) * scale,
rbound = (w - m[3]) * scale;
// limit translation to thresholds
translation = [
Math.max(Math.min(translation[0], rbound), lbound),
Math.max(Math.min(translation[1], bbound), tbound)
];
d3.select(".drawarea")
.attr("transform", "translate(" + translation + ")" +
" scale(" + scale + ")");
}
// 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);
}
/*function click(node)
{
alert(node.name);
//document.getElementById('gid').innerHTML = "sucess";
document.getElementById('gid').innerHTML = node.gid;
document.getElementById('gname').innerHTML = node.name;
document.getElementById('gmethod').innerHTML = node.method;
document.getElementById('gmtype').innerHTML = node.methodtype;
document.getElementById('gdate').innerHTML = node.date;
document.getElementById('gcountry').innerHTML = node.country;
document.getElementById('gloc').innerHTML = node.location;
document.getElementById('gcname').innerHTML = node.cname;
document.getElementById('gref').innerHTML = node.ref;
document.getElementById('gpid1').innerHTML = node.gpid1;
document.getElementById('gpid2').innerHTML = node.gpid2;
//document.getElementById('try').value = d.name;
}*/