How to add remove certain json arrays from dropdown - javascript

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.

Related

D3 force layout graph zoom functionality

I new in js and can't solve problem i faced by myself, so I will be glad for any advices or helps.
In my project I created force layout graph.
What I should do is to add zoom in and zoom out functionality for my graph.
I created little example to show what problem I faced.
function myGraph(el){
this.addNode = function (id, category, opened, parentT, name, nodeType, countLinks, dob, country, childsCount) {
var parent = [];
parent.push(parentT);
nodes.push({ "id": id, "category": category, "opened": opened, "parent": parent, "name": name, "nodeType": nodeType, "countLinks": countLinks, "dob": dob, "country": country, "childCount": childsCount });
update();
}
this.addLink = function (sourceId, targetId, type) {
var sourceNode = findNode(sourceId);
var targetNode = findNode(targetId);
if ((sourceNode !== undefined) && (targetNode !== undefined)) {
links.push({ "source": sourceNode, "target": targetNode, "type": type });
update();
}
}
var findNode = function (id) {
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].id === id)
return nodes[i]
};
}
var w = 360,
h = 200;
var vis = this.vis = d3.select(el).append("svg:svg")
.attr("id", "mySvg")
.attr("width", w)
.attr("height", h)
.attr("viewBox", "0 0 " + w + " " + h)
.call(d3.behavior.zoom().scaleExtent([-0.5, 1]).on("zoom", redraw))
var g = vis.append('svg:g')
function redraw(e) {
if (!e) e = window.event;
if (e.type == "wheel" || e.shiftKey == true) {
g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
}
var force = d3.layout.force()
.gravity(0.05)
.distance(100)
.charge(-200)
.size([w, h]);
var nodes = force.nodes(),
links = force.links();
var hiddenType = [];
g.append("g").attr("class", "links");
g.append("g").attr("class", "nodes");
var update = function () {
for (var i=0; i<links.length; i++) {
if (i != 0 &&
links[i].source == links[i-1].source &&
links[i].target == links[i-1].target) {
links[i].linknum = links[i-1].linknum + 1;
}
else {links[i].linknum = 1;};
};
var myLink = g.select(".links").selectAll(".link");
myLink.remove();
var link = g.select(".links").selectAll(".link")
.data(links);
link.enter().append("polyline")
.attr("class", "link")
.attr("type", function (d) { return "link_" + d.type; })
link.exit().remove();
var node = g.select(".nodes").selectAll(".node")
.data(nodes, function (d) { return d.id; })
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("links", function (d) { return d.countLinks })
.attr("type", function (d) { return d.nodeType })
.on("mousedown", mousedown)
.call(force.drag);
nodeEnter.append("circle")
.attr("r", "10px")
.attr("x", "-8px")
.attr("y", "-8px")
.attr("width", "16px")
.attr("height", "16px")
.style("fill", "white")
.style("stroke", "#ccc")
nodeEnter.append("rect")
.attr("pointer-events", "none")
.attr("class", "shape")
.attr("width", "250px")
.attr("height", "150px")
.style("fill", "transparent")
nodeEnter.append("text")
.attr("pointer-events", "none")
.attr("class", function (d) { return "nodetext_" + d.id })
.attr("y", "-10")
.text(function (d) { return d.id })
nodeEnter.append("title")
.text(function (d) { return d.id });
node.exit().remove();
function mousedown(d) {
d.fixed = true;
}
force.on("tick", function () {
link.attr("points", function(d){
if (d.source.y > d.target.y) {
return d.source.x + "," + d.source.y + " " + (d.source.x + ((d.target.x - d.source.x) / 2)) + "," + (d.target.y + ((d.source.y - d.target.y) / 2) + (15 * (d.linknum - 1))) + " " + d.target.x + "," + d.target.y;
}
if (d.source.y < d.target.y) {
return d.source.x + "," + d.source.y + " " + (d.source.x + ((d.target.x - d.source.x) / 2)) + "," + (d.source.y + ((d.target.y - d.source.y) / 2) + (15 * (d.linknum - 1))) + " " + d.target.x + "," + d.target.y;
}
})
node.attr("transform", function (d) {
if (d.fixed !== true) {
return "translate(" + d.x + "," + d.y + ")";
}
else {
return "translate(" + d.px + "," + d.py + ")";
}
});
});
force.start();
}
update();
}
graph = new myGraph("#graph");
graph.addNode("A")
graph.addNode("B")
graph.addNode("C")
graph.addLink("A", "B")
graph.addLink("A", "C")
https://jsfiddle.net/IMykytiv/nsxL8c52/
So problem is:
In my graph users can drag nodes in any direction, after that node's position becomes fixed. When I added zooming I can't drag nodes because zooming works first, so I added condition that zoom works only when shift key is pressed. So now I can both drag nodes and zoom.
But now I faced problem that if I drag node and try to zoom with mouse wheel it changed transform not from mouse position but from another point and I can't understand why. If I remove shift key condition zooming works as expected.
I finaly found solution and it was preaty easy.
Instead of adding condition with shift key pressed all I need to do is to prevent trigger zoom function on start draggin node event:
var drag = force.drag()
.on("dragstart", function (d) {
d3.event.sourceEvent.stopPropagation();
});
Updated jsfiddle here:
https://jsfiddle.net/IMykytiv/nsxL8c52/2/
Hope that it will be useful for anyone :)

d3.js radial treed downloads differently to svg

I was creating a radial tree and trying to download it to SVG but it has some issues
It downloads with those black thick strokes which are not displayed on the webpage.
Any idea where the black lines are coming from?
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
g = svg.append("g").attr("transform", "translate(" + (width / 2 - 15) + ","
+ (height / 2 + 25) + ")");
var stratify = d3.stratify()
.parentId(function(d) {
console.log(d.id.substring(0, d.id.lastIndexOf(".")));
return d.id.substring(0, d.id.lastIndexOf(".")); });
var tree = d3.cluster()
tree.size([360, 360])
tree.separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) /
a.depth; });
d3.csv("flare.csv", function(error, data) {
if (error) throw error;
var root = tree(stratify(data)
.sort(function(a, b) { return (a.height - b.height + 100) ||
a.id.localeCompare(b.id); }));
var link = g.selectAll(".link")
.data(root.descendants().slice(1))
.enter().append("path")
.attr("class", "link")
.attr("d", function(d) {
return "M" + project(d.x, d.y)
+ "C" + project(d.x, (d.y + d.parent.y) / 2)
+ " " + project(d.parent.x, (d.y + d.parent.y) / 2)
+ " " + project(d.parent.x, d.parent.y);
});
link.attr('stroke', function(d) {
if (d.id.startsWith("Mother.Biological")){
return "#386eff";
}
if (d.id.startsWith("Mother.Env")){
return "#45cbf2";
}
else return '#70f2ad';
});
var node = g.selectAll(".node")
.data(root.descendants())
.enter().append("g")
.attr("class", function(d) { return "node" + (d.children ? " node--
internal" : " node--leaf"); })
.attr("transform", function(d) { return "translate(" + project(d.x,
d.y)
+ ")"; });
node.append("circle")
.attr("r", function(d) {
console.log(d.value);
if (d.id == "Mother") return 4.4;
else return 2.4;
} )
.style('fill', function(d) {
if (d.id.startsWith("Mother.Biological")){
return "#386eff";
}
if (d.id.startsWith("Mother.Env")){
return "#45cbf2";
}
if (d.id.startsWith("Mother.Biological")){
return "#386eff";
}
if (d.id.startsWith("Mother.Form")){
return '#70f2ad';
}
d.color = 'red';
return d.color});
node.append("text")
.attr("dy", ".31em")
.attr("x", function(d) { return d.x < 180 === !d.children ? 6 : -6; })
.style("text-anchor", function(d) { return d.x < 180 === !d.children ?
"start" : "end"; })
.attr("transform", function(d) { return "rotate(" + (d.x < 180 ? d.x - 90
: d.x + 90) + ")"; })
.text(function(d) { return d.id.substring(d.id.lastIndexOf(".") + 1); });
});
function project(x, y) {
var angle = (x - 90) / 180 * Math.PI, radius = y;
return [radius * Math.cos(angle), radius * Math.sin(angle)];
}
d3.select("#download")
.on("mouseover", writeDownloadLink);
function writeDownloadLink(){
var html = d3.select("svg")
.attr("title", "svg_title")
.attr("version", 1.1)
.attr("xmlns", "http://www.w3.org/2000/svg")
.node().parentNode.innerHTML;
d3.select(this)
.attr("href-lang", "image/svg+xml")
.attr("href", "data:image/svg+xml;base64,\n" + btoa(html))
.on("mousedown", function(){
if(event.button != 2){
d3.select(this)
.attr("href", null)
.html("Use right click");
}
})
.on("mouseout", function(){
d3.select(this)
.html("Download");
});
};
It looks ok in any browser but when I download it and convert it to SVG or EFM it comes back with those lines.
Page that you provided contains style tag. I'm not sure how exactly do you export SVG, but some css rules seems to be lost along the way.
In similar case I managed to get current css properties and put them into style property:
d3.selectAll('...').each(function() {
var that = d3.select(this);
['stroke', 'stroke-width', 'opacity', 'fill', ...].forEach(function(property) {
that.style(property, that.style(property))
});
});
Hope this will help you.

d3js arc height tweening

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

How to initiate zoomability in a Sunburst with selection from dropdown

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!

d3.js Tree orientation and node clicking

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;
}*/

Categories