d3.js - Text inside arc is misaligned/overlapped - d3.js

I am drawing a pie chart and in each arc i write the text in the centre. However when the arc is too small, the text gets misaligned. How do i restrict writing the text if the arc is too thin. Is there a way to identify the arc and not write the text.
My code:
var arc = d3.svg.arc()
.outerRadius(radius - 45)
.innerRadius(radius -200);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {return d.Components;});
var g = svg.selectAll(".arc")
.data(pie(newdata))
.enter().append("g")
.attr("class", "arc")
.attr("id", function(d,i) {return "group" + i})
g.append("path")
.attr("d", arc)
.style("fill","#FFFFFF")
.transition()
.ease("bounce")
.duration(1000)
.delay(function(d, i) {return i * 500;})
.style("fill", function(d,i)
{
var c = d.data.Source;
if (c=="GREEN")
{
return "#78a22f";
}
else if (c=="RED")
{
return "#a00000";
}
else if (c=="AMBER")
{
return "#Ffb400";
}
else
{
return "#DADCF6";
}
});
g.append("text")
.attr("transform", function(d)
{
//comment
var c = arc.centroid(d);
var param,param1
param = c[1]- 20;
param1= c[0]- 38;
return "translate(" + param1 + "," + param + ")";
})
.attr("dy", ".35em")
.style("text-anchor", "middle")
.attr("style","font-family: Arial;border: solid 1px" )
.transition()
.ease("bounce")
.duration(1000)
.delay(function(d, i) {return i * 500;})
.text(function(d) {
return ((d.data.Status));
}
});
g.append("text")
.attr("transform", function(d)
{
var c = arc.centroid(d);
var param = c[1];
var param1=c[0];
return "translate(" + param1 + "," + param + ")";
})
.attr("dy", ".35em")
.style("text-anchor", "middle")
.transition()
.ease("bounce")
.duration(1000)
.delay(function(d, i) {return i * 500;})
.text(function(d) {
if (eval(d.data.Components) >0)
{
return (Number(d.data.Components).toFixed(0)) + " (" + (Number(d.data.Percentage).toFixed(1) + "%)");
}
});
data is like:
"Source","Components","Percentage","Business Unit","Status","BUId"
"RED","20","4.77","Financial & Risk - ALL","Analyzed","67001003"
"AMBER","2","0.48","Financial & Risk - ALL","Identified","67001003"
"GREEN","21","5.01","Financial & Risk - ALL","Approved","67001003"
"PALEBLUE","83","19.81","Financial & Risk - ALL","Unmapped","67001003"
"GREY","293","69.93","Financial & Risk - ALL","Not Applicable","67001003"

Related

D3 dashboard chart data bind from json or csv

I am new to D3 charts
i am using D3 dashboard chart following link
http://bl.ocks.org/diethardsteiner/3287802
here the datas are given by variables.
I don't want to get the value from variable and i want to get the value from json file.
Before the data are stored in a variable.
################ FORMATS ##################
-------------------------------------------
*/
var formatAsPercentage = d3.format("%"),
formatAsPercentage1Dec = d3.format(".1%"),
formatAsInteger = d3.format(","),
fsec = d3.time.format("%S s"),
fmin = d3.time.format("%M m"),
fhou = d3.time.format("%H h"),
fwee = d3.time.format("%a"),
fdat = d3.time.format("%d d"),
fmon = d3.time.format("%b")
;
/*
############# PIE CHART ###################
-------------------------------------------
*/
function dsPieChart(){
var dataset = [
{category: "ACC", measure: 0.30},
{category: "B56", measure: 0.25},
{category: "MAB", measure: 0.15},
]
;
var width = 400,
height = 400,
outerRadius = Math.min(width, height) / 2,
innerRadius = outerRadius * .999,
innerRadiusFinal = outerRadius * .5,
innerRadiusFinal3 = outerRadius* .45,
color = d3.scale.category20()
;
var vis = d3.select("#pieChart")
.append("svg:svg")
.data([dataset])
.attr("width", width)
.attr("height", height)
.append("svg:g")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")")
;
var arc = d3.svg.arc()
.outerRadius(outerRadius).innerRadius(innerRadius);
var arcFinal = d3.svg.arc().innerRadius(innerRadiusFinal).outerRadius(outerRadius);
var arcFinal3 = d3.svg.arc().innerRadius(innerRadiusFinal3).outerRadius(outerRadius);
var pie = d3.layout.pie()
.value(function(d) { return d.measure; });
var arcs = vis.selectAll("g.slice")
.data(pie)
.enter()
.append("svg:g")
.attr("class", "slice")
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.on("click", up)
;
arcs.append("svg:path")
.attr("fill", function(d, i) { return color(i); } )
.attr("d", arc)
.append("svg:title")
.text(function(d) { return d.data.category + ": " + formatAsPercentage(d.data.measure); });
d3.selectAll("g.slice").selectAll("path").transition()
.duration(750)
.delay(10)
.attr("d", arcFinal )
;
arcs.filter(function(d) { return d.endAngle - d.startAngle > .2; })
.append("svg:text")
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.attr("transform", function(d) { return "translate(" + arcFinal.centroid(d) + ")rotate(" + angle(d) + ")"; })
.text(function(d) { return d.data.category; })
;
function angle(d) {
var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
return a > 90 ? a - 180 : a;
}
// Pie chart title
vis.append("svg:text")
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text("Building")
.attr("class","title")
;
function mouseover() {
d3.select(this).select("path").transition()
.duration(750)
.attr("d", arcFinal3)
;
}
function mouseout() {
d3.select(this).select("path").transition()
.duration(750)
.attr("d", arcFinal)
;
}
function up(d, i) {
updateBarChart(d.data.category, color(i));
updateLineChart(d.data.category, color(i));
}
}
dsPieChart();
now i am trying to get the data by folowing way.
I dont know this is correct way or not can anyone help me
################ FORMATS ##################
-------------------------------------------
*/
var formatAsPercentage = d3.format("%"),
formatAsPercentage1Dec = d3.format(".1%"),
formatAsInteger = d3.format(","),
fsec = d3.time.format("%S s"),
fmin = d3.time.format("%M m"),
fhou = d3.time.format("%H h"),
fwee = d3.time.format("%a"),
fdat = d3.time.format("%d d"),
fmon = d3.time.format("%b")
;
/*
############# PIE CHART ###################
-------------------------------------------
*/
function dsPieChart(){
var width = 400,
height = 400,
outerRadius = Math.min(width, height) / 2,
innerRadius = outerRadius * .999,
// for animation
innerRadiusFinal = outerRadius * .5,
innerRadiusFinal3 = outerRadius* .45,
color = d3.scale.category20() //builtin range of colors
;
});
var vis = d3.select("#pieChart")
.append("svg")
d3.json("readme.json", function(error, root) {
if (error) throw error;
.data([root])
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")")
})
;
var arc = d3.svg.arc()
.outerRadius(outerRadius).innerRadius(innerRadius);
var arcFinal = d3.svg.arc().innerRadius(innerRadiusFinal).outerRadius(outerRadius);
var arcFinal3 = d3.svg.arc().innerRadius(innerRadiusFinal3).outerRadius(outerRadius);
var pie = d3.layout.pie()
.value(function(d) { return d.measure; });
var arcs = vis.selectAll("g.slice")
.data(pie)
.enter()
.append("g")
.attr("class", "slice")
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.on("click", up)
;
arcs.append("path")
.attr("fill", function(d, i) { return color(i); } )
.attr("d", arc)
.append("title")
.text(function(d) { return d.data.category + ": " + formatAsPercentage(d.data.measure); });
d3.selectAll("g.slice").selectAll("path").transition()
.duration(750)
.delay(10)
.attr("d", arcFinal )
;
arcs.filter(function(d) { return d.endAngle - d.startAngle > .2; })
.append("text")
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.attr("transform", function(d) { return "translate(" + arcFinal.centroid(d) + ")rotate(" + angle(d) + ")"; })
.text(function(d) { return d.data.category; })
;
function angle(d) {
var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
return a > 90 ? a - 180 : a;
}
vis.append("text")
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text("Building")
.attr("class","title")
;
function mouseover() {
d3.select(this).select("path").transition()
.duration(750)
.attr("d", arcFinal3)
;
}
function mouseout() {
d3.select(this).select("path").transition()
.duration(750)
.attr("d", arcFinal)
;
}
function up(d, i) {
updateBarChart(d.data.category, color(i));
updateLineChart(d.data.category, color(i));
}
}
dsPieChart();
can any one give a correct solution
Thanks,
Vinoth
Just create a JSON file with this structure:
[{
"category": "ACC",
"measure": 0.30
}, {
"category": "B56",
"measure": 0.25
}, {
"category": "MAB",
"measure": 0.15
}]
And use d3.json:
d3.json("data.json", function(dataset){
//code here
});
Here is a plunker showing it: https://plnkr.co/edit/OUjPNY3W2aXXCSxvm4tZ?p=preview

Highlight path in d3 tree is not working in IE

I created tree layout as in JSFiddle example http://jsfiddle.net/oo66o0q0/15/.
Requirement is path should highlighted in red and with extra width when user click on node's right click menu "Highlight Route" option.
This is working in chrome correctly but in IE highlighted route color becomes black.
If I remove markers then it works in IE as well.
How to resolve this issue in IE but not removing markers?
function treeInitialize(graphData){
diagramLayout = d3.select("#diagramLayout")
.attr("id", "diagramLayout")//set id
.attr("width", width)//set width
.attr("height", height)//set height
.append("g")
.attr("transform", "translate(" + 20 + "," + 20 + ")")
markerRefx = 40;
var data2 = graphData.links.filter(function(l){
if(l.target == undefined && l.source == undefined){
return false;
}else{
return true;
}
});
data2.push(JSON.parse('{"target":"glossforArrow","source":""}'))
var treeData = d3.stratify().id(function(d){ return d.target; }).parentId(function(d) {
return d.source;
})(data2)
nodes = d3.hierarchy(treeData, function(d) {return d.children;});
var levelWidth = [1];
var childCount = function(level, n) {
if(n.children && n.children.length > 0) {
if(levelWidth.length <= level + 1) levelWidth.push(0);
levelWidth[level+1] += n.children.length;
n.children.forEach(function(d) {
childCount(level + 1, d);
});
}
};
childCount(0, nodes);
newHeight = d3.max(levelWidth) * 100;
var tree = d3.tree().size([height, width])
tree.size([newHeight,height/2]);
tree.separation(function (a, b) {
return a.parent == b.parent ? 50 : 100;
});
nodes = tree(nodes);
treeLayout(nodes);
function treeLayout(nodes){
var node = diagramLayout.selectAll(".node");
node = node.data(nodes.descendants());
var link = diagramLayout.selectAll(".link")
.data(nodes.descendants().slice(1))
.enter().append("path")
.attr("class", "link")
.attr("fill", "none")
.attr("stroke", "#000")
.attr("stroke-width", "1px")
.attr("stroke-opacity", "0.3")
.attr("d",connector)
nodes.descendants().slice(1).forEach(function(d) {
var mark = diagramLayout.append("svg:defs").selectAll("marker")//
.data(["start"]) // Different link/path types can be defined here
.enter().append("svg:marker") // This section adds in the arrows
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", -markerRefx)
.attr("refY", 0)
.attr("markerWidth", 5)
.attr("markerHeight", 5)
.attr("orient", "auto")
.attr("stroke", "#000")
.attr("fill", "#000")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5")
.style("stroke-width", "0.3px")
.attr("transform","rotate(180,5, 0)");
});
link.attr("marker-start", "url(#start)")
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("height", nodeHeight)
.attr("width", nodeWidth)
nodeEnter.attr("transform", function(d) {
return "translate(" + project(d.x, d.y) + ")";
}).on('contextmenu', menuCall);
var nodeIcon = nodeEnter.append("rect")
.attr("class", "rect")
.attr("x", -20)
.attr("y", -20)
.attr("rx", 10)
.attr("width", 40)
.attr("height", 40)
.attr("stroke-width", function(d) { return Math.sqrt(2); })
.attr("stroke-opacity", "0.3")
.attr("stroke", "#000" )
.attr("fill", "blue" )
//wrap(nodeText, 8)
}
}
function connector(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);
}
function project(x, y) {
return [x,y];
}
function menuCall(di,i) {
var nodeClicked = d3.select(this);
var menuitems = ["Highlight route"];
d3.selectAll('.context-menu').data([1])
.enter()
.append('div')
.attr('class', 'context-menu');
// close menu
d3.select('body').on('click.context-menu', function() {
d3.select('.context-menu').style('display', 'none');
});
// this gets executed when a contextmenu event occurs
d3.selectAll('.context-menu')
.html('')
.append('ul')
.selectAll('li')
.data(menuitems).enter()
.append('li')
.on('click' , function(d) {
// d3.select('.context-menu').style('display', 'none');
if(d=="Highlight route"){
var id = nodeClicked.datum().data.id;
var node = diagramLayout.selectAll(".node");
var link = diagramLayout.selectAll(".link");
link.style("stroke","black").style("stroke-width", "1.5px")
var linkSelected = link.filter(function (d, i) {
console.log(d.data.id)
console.log(id)
return d.data.id === id;});
linkSelected.style("stroke", "red").style("stroke-width", "5px");
}
d3.select('.context-menu').style('display', 'none');
}).text(function(di) { return di; });
d3.select('.context-menu').style('display', 'none');
// show the context menu
d3.select('.context-menu')
.style('left', (d3.event.pageX - 2) + 'px')
.style('top', (d3.event.pageY - 2) + 'px')
.style('display', 'block');
d3.event.preventDefault();
}
Looks like a bug in IE. If you inspect the DOM after you apply the highlight, IE reports that the inline style has overridden the sheet style (as it should), but the path does not update:
The only fix I can think us is to remove the sheet stroke style on class link
.link {
stroke-opacity: .6;
}
And just apply all the styles in-line.
Updated fiddle.

D3.JS <tspan> rotation in sunburst

I am building my own sunburst diagram from this example
by adding multiline captions as .
for(i = 0; i < MAX_LINES; i++){
var text = g.append("text")
.attr("transform", function(d) { return "translate(" + getCentroid(d) + ")rotate(" + textRotation(d) + ")"; })
.attr('text-anchor', function (d) { return textRotation(d) > 180 ? "end" : "start"; })
.attr("dx", "0")
.attr("dy", "0em")
.attr("class", function(d) { return setStyle(d); })
.style("fill", function(d) { return setColor(d); })
.style("text-anchor", "middle")
.append("tspan")
.attr("dy", function(d) { return getDY(d, i); } )
.text(function(d) { return getLine(d, i); });
//.text(function(d) { return d.name; });
}
This works absolutely fine on initial state, but when you are
zooming it by clicking on certain partition everything becomes
messy. The script only moves first line element and doesn't
hide other elements shouldn't be on screen.
.duration(500)
.attrTween("d", arcTween(d))
.each("end", function(e, i) {
if (e.x >= d.x && e.x < (d.x + d.dx)) {
var arcText = d3.select(this.parentNode).select("text");
arcText.transition().duration(750)
.attr("opacity", 1)
.attr("transform", function(d) { return "translate(" + getCentroid(d) + ")rotate(" + textRotation(d) + ")"; })
.attr('text-anchor', "middle")
}
});
}
});
How I can transform for every partition?
I have tried to do selection by "tspan" or its style class.
Is it possible to completely renew block by reassigning name
and recreating 's

updating labels when switching dataset (+removing older one)

I've been drawing a planetarium with planets and labels on it :
svg.append("circle").attr("r", 20).attr("cx", w/2)
.attr("cy", h/2).attr("class", "sun");
svg.append("text").attr("x", w/2)
.attr("y", h/2).attr("text-anchor", "middle").attr("fill", "grey").text("VICTOR HUGO");
var container = svg.append("g")
.attr("transform", "translate(" + w/2 + "," + h/2 + ")")
var orbit = container.selectAll(".orbit")
.data(dataset, key)
.enter()
.append("circle")
.attr("class", "orbit")
.attr("r", 0);
//function(d) {return (d.key * ((w/2)/151) + 20); });
var planets = container.selectAll(".planet")
.data(dataset, key)
.enter()
.append("circle")
.attr("class", "planet")
.attr("r", function(d) {return 5;})
.attr("cx", function(d) {return d.x; })
.attr("cy", function(d) {return d.y; })
.on("mouseover", function(d, i) {
stopTooltip = false
showTooltip(d);
});
d3.select("svg").on("click", function(d) {stopTooltip = true;});
var texts = container.selectAll(".text")
.data(dataset, key)
.enter()
.append("text")
.attr("class", "text")
.attr("dx", function(d) {return d.x;})
.attr("dy", ".35em")
.text(function(d) {return d.titre});
Then, I've been adding a legend and a click function, so that when you click on one or another of the legend subtitle, the dataset is updated (if you look at the tooltips, it is indeed updated).
////////////////////////Legend//////////////////////////////////
update = function(newDataset, key){
var newplanets = container.selectAll(".planet").data(newDataset, key);
newplanets.enter().append("circle");
newplanets.transition()
.duration(0)
.attr("r", function(d) {return 5;})
.attr("cx", function(d) {return d.x; })
.attr("cy", function(d) {return d.y; })
.on("mouseover", function(d, i) {
stopTooltip = false
showTooltip(d);
});
newplanets.exit().remove();
var newtexts = container.selectAll(".text").data(newDataset, key);
newtexts.enter().append("text");
newtexts.transition()
.duration(0)
.attr("class", "text")
.attr("dx", function(d) {return d.x;})
.attr("dy", ".35em")
.text(function(d) {return d.titre});
newtexts.exit().remove();
}
var legendRectSize = 7;
var legendSpacing = 20;
var VictorHugoClass = [
{ "VHClassName": '...Auteur (oeuvre)', "VHClass": r990o, "color": "#0000FF" },
{ "VHClassName": '...Auteur (expression)', "VHClass": r990e, "color": "#FBA10D" },
];
//Initiate container around Legend
var legendContainer = svg.append("g").attr("class","legendContainer")
.attr("transform", "translate(" + 30 + "," + (h - 90) + ")");
//Create title of Legend
var legendTitle = legendContainer.append('text')
.attr('x', 0)
.attr('y', legendRectSize - legendSpacing)
.attr("dy", "1em")
.attr('class', 'legendTitle')
.attr('transform', function() {
var height = legendRectSize + legendSpacing;
var offset = height * VictorHugoClass.length / 2;
var horz = -2 * legendRectSize;
var vert = -2.3 * height - offset;
return 'translate(' + horz + ',' + vert + ')';
})
.attr("fill", "black")
.text("Victor Hugo en tant que...")
.call(wrap, 200);
//Create container per circle/text pair
var legend = legendContainer
.selectAll('.legend')
.data(VictorHugoClass)
.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', function(d, i) {
var height = legendRectSize + legendSpacing;
var offset = height * VictorHugoClass.length / 2;
var horz = -2 * legendRectSize;
var vert = i * height - offset;
return 'translate(' + horz + ',' + vert + ')';
})
.on("click", function(d) {
update(d.VHClass, d.key);
});
//Append circles to Legend
legend.append('circle')
.attr('r', legendRectSize)
.attr('cx', 4)
.attr('cy', legendRectSize/2 - legendSpacing)
.attr("opacity", 1)
.style("fill", "white")
.style('stroke', function(d) {return d.color;});
//Append text to Legend
legend.append('text')
.attr('x', legendRectSize + legendSpacing/2)
.attr('y', legendRectSize - legendSpacing)
.attr("fill", "black")
.text(function(d) { return d.VHClassName; });
Nevertheless, the labels won't update with the planets, and some of the data of the former dataset are still remaining when the second dataset is loaded into the visualization. My Plunker is here for more details : http://plnkr.co/edit/UnhqCZhME7ymxdIbpcIj?p=preview
Thank you very much for your help in this...

d3 donut chart transistion change

Another d3 newbie question here.
I am trying to transition change a donut chart with grouped nested data. Here's what I have now.
http://bricbracs.com/test/
So when I click on a segment arc like New York it will update with data from the dept column with a nested function so I get this. I am close. I have the data grouped. I need help redrawing the donut.
http://bricbracs.com/test1/
Here is a csv file.
status,dept,city,points
temp,finance,New York,33
contract,HR,London,12
contract,HR,New York,11
casual,shop,London,43
contract,shop,Paris,51
temp,finance,London,7
contract,office,New York,61
contract,shop,London,31
temp,office,New York,16
contract,office,London,19
temp,finance,London,7
contract,office,New York,61
contract,sales,London,31
temp,finance,New York,16
contract,sales,Paris,19
Here is the d3 script. Thanks in advance.
<script>
var width = 960,
height = 500,
radius = Math.min(width, height) / 2;
var color = d3.scale.category20();
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(radius - 70);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d.values;
});
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
svg.style("cursor","pointer")
d3.csv("data.csv", function(error, data) {
var data = d3.nest()
.key(function(d) {
return d.city;
})
.rollup(function(d) {
return d3.sum(d, function(g) {
return g.points;
});
}).entries(data);
var g = svg.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.attr("stroke", "white")
.attr("stroke-width", 0.5)
.style("fill", function(d) {
return color(d.data.key);
})
.on("mouseover", function (d) {
d3.select("#tooltip")
.style("left", d3.event.pageX + "px")
.style("top", d3.event.pageY + "px")
.style("opacity", .75)
.select("#value")
.text(d.value.toLocaleString())
document.getElementById("demo").innerHTML =d.data.key
})
.on("mouseout", function () {
d3.select("#tooltip")
.style("opacity", 0);
console.log("OUT")
})
.on("mousemove", function () {
d3.select("#tooltip")
.style("left", (d3.event.pageX +20) + "px")
.style("top", d3.event.pageY + "px+50")
})
.on("click", function() {
change()
});
g.append("text")
.attr("transform", function(d) {
var c = arc.centroid(d),
x = c[0],
y = c[1],l
h = Math.sqrt(x*x + y*y);
return "translate(" + arc.centroid(d) + ")";
})
//.attr("dy", "1em")
.style("text-anchor", "middle")
.text(function(d) {
return d.data.key
})
function change() {
var data = d3.nest()
.key(function(d) {
return d.dept;
})
.rollup(function(d) {
return d3.sum(d, function(g) {
return g.points;
});
}).entries(data);
var path = svg.selectAll("path");
path = path.data(pie(data), function(d) { return d.data.key; })
path.enter().append("path").attr("fill", function(d) {return color(d.data.key); })
path.exit().remove()
path.attr("d", arc)
}
});

Resources