Hi I am new in d3js so I am unable to use mouseover event in given code of pie chart...i have a with id named chart so how can I create some class that mouseover event and show a label?
Here is the code that I am using to draw pie chart:
var w = 300;
var h = 300;
var dataset = [
{"year":"2017-07-01","value":"5"},
{"year":"2017-07-02","value":"10"},
{"year":"2017-07-03","value":"15"},
{"year":"2017-07-04","value":"20"},
{"year":"2017-07-05","value":"25"},
{"year":"2017-07-06","value":"30"},
{"year":"2017-07-07","value":"35"},
{"year":"2017-07-08","value":"40"},
{"year":"2017-07-09","value":"45"},
{"year":"2017-07-10","value":"50"},
{"year":"2017-07-11","value":"55"},
{"year":"2017-07-12","value":"60"},
{"year":"2017-07-13","value":"65"},
{"year":"2017-07-14","value":"70"}
];
var outerRadius = w / 2;
var innerRadius = 0;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.layout.pie()
.value(function(d) {
return d.value;
});
var color = d3.scale.category20();
var svg = d3.select("#chart")
.append("svg")
.attr("width", w)
.attr("height", h);
var arcs = svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")");
arcs.append("path")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc);
arcs.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text(function(d) {
return d.value;
});
I use a tooltip:
var popup=d3.select("body").append("div").attr("class","tooltip").style("opacity",0);
Then to call the tooltip, add an event listener to the nodes (I guess it would be arcs for you, but I haven't done pie charts):
nodes.on("mouseover", fade(.1,"over")).on("mouseout",fade(.8,"out"));
Then the function to put the tooltip near the node (or pie in this case):
function fade (opacity, event){
return function (d){
if(event === "over"){
popup.transition().duration(100).style("opacity", .9).style("display", "inline-block");
popup.html("Year: " + d.year + "</br> Value: " + d.value)
.style("left", (d3.event.pageX + 20) + "px")
.style("top", (d3.event.pageY - 20) + "px");
d3.select(this).classed("node-mouseover", true);}
else if(event==="out"){
popup.transition().duration(100).style("opacity",0);
d3.select(this).classed("node-mouseover",false);
}}}
There are other ways of doing it, but this seems to be pretty popular this example is similar.
Edit: check out bl.ocks.org for more examples.
Related
i have added the D3 script to my web application which is developed by angularjs.
the D3 graph is drawn but multiple graphs are appear every time i access to the tabs.
Below is the script i used.
<script type="text/javascript">
data = [{"value":200},
{"value":100}];
var w = 300,
h = 300,
r = 100,
color = d3.scale.category20c();
/*var canvas = d3.select("body").append("svg:svg").data([data])
.attr("width", w)
.attr("height", h)
.append("svg:g")
.attr("transform", "translate(" + r + "," + r + ")")*/
var canvas = d3.select("body svg:svg");
if(!svg){
canvas = d3.select("body")
.append("svg:svg").data([data])
.attr("width", w)
.attr("height", h)
.append("svg:g")
.attr("transform", "translate(" + r + "," + r + ")")
}
var arc = d3.svg.arc()
.outerRadius(r);
var pie = d3.layout.pie()
.value(function(d) { return d.value; });
var arcs = canvas.selectAll("g.slice")
.data(pie)
.enter()
.append("svg:g")
.attr("class", "slice");
arcs.append("svg:path")
.attr("fill", function(d, i) { return color(i); } )
.attr("d", arc);
arcs.append("svg:text")
.attr("transform", function(d) {
d.innerRadius = 0;
d.outerRadius = r;
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text(function(d, i) { return data[i].value; });
</script>
i added this script to the view that i wanted to show the graph.but after accessing to the specific tab the graph is show in every tab of my application.
As above image the grpagh is generated every time access to the tab/view.
can anyone help me this.
Thanks
Why don't you want to use unique element with id for your chart?
var canvas = d3.select("body svg:svg");
if(!svg){
canvas = d3.select("body")
Try to change it to something like
var canvas = d3.select("#yourId svg:svg");
if(!svg){
canvas = d3.select("#yourId")
Also add <div id='yourId'></div> tag to a tab, where your chart should be
Try removing svg before rendering another svg
d3.select("svg").remove();
What I'm trying to do is make two charts display in the same field, one to show the time spent working vs. the time spent idling, and the other chart to show whether the machine is currently working or idling.
I want the chart that shows the machine idling to be smaller than the first and fit inside it. I've been able to make both charts but I am unable to combine them in the way that I want them to.
[what I have right now]
[what I'd like to do]
Here is my code:
<!DOCTYPE html>
<html lang="en">
<div id="chart-center-jc1" align="center"></div>
<!--this line control location of the SVG chart-->
<script src="d3/d3.v3.min.js"></script>
<script>
var radius = 80,
padding = 10;
var radius2 = 25,
padding = 10;
var color = d3.scale.ordinal()
.range([ "#fc0303", "#21d525", "#d0cece", "#a05d56", "#d0743c", "#ff8c00"]);
var arc = d3.svg.arc()
.outerRadius(radius)
.innerRadius(radius - 30);
var arc2 = d3.svg.arc()
.outerRadius(radius2)
.innerRadius(radius2 - 25);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.population; });
var pie2 = d3.layout.pie()
.sort(null)
.value(function(d) { return d.population; });
d3.csv("M1 Summary.csv", function(error, data) {
if (error) throw error;
color.domain(d3.keys(data[0]).filter(function(key) { return key !=="Machine"; }));
data.forEach(function(d) {
d.ages = color.domain().map(function(name) {
return {name: name, population: +d[name]};
});
});
var legend = d3.select("#chart-center-jc1").append("svg")
.attr("class", "legend")
.attr("width", radius * 2)
.attr("height", radius * 2)
.selectAll("g")
.data(color.domain().slice().reverse())
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", 24)
.attr("y", 9)
.attr("dy", ".35em")
.text(function(d) { return d; });
var svg = d3.select("#chart-center-jc1").selectAll(".pie")
.data(data)
.enter().append("svg")
.attr("class", "pie2")
.attr("width", radius * 2)
.attr("height", radius * 3)
.append("g")
.attr("transform", "translate(" + radius + "," + radius + ")");
svg.selectAll(".arc")
.data(function(d) { return pie(d.ages); })
.enter().append("path")
.attr("class", "arc")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.name); });
svg.selectAll(".arc2")
.data(function(d) { return pie2(d.ages); })
.enter().append("path")
.attr("class", "arc2")
.attr("d", arc2)
.style("fill", function(d) { return color(d.data.name); });
});
The key is to append one svg onto another:
var svg = d3.select("#chart-center-jc1").append("svg")
.attr("width", radius * 2)
.attr("height", radius * 3)
.attr("class","outerPie")
.append("g")
.attr("transform", "translate(" + radius + "," + radius + ")");
var svg2 = d3.select(".outerPie").append("svg")
.attr("width", radius * 2)
.attr("height", radius * 3)
.attr("class","innerPie")
.append("g")
.attr("transform", "translate(" + radius + "," + radius + ")");
Note that both svgs have the same height, width, and translate. This is because they are on top of one another, and you want to position the second in the center of the first.
See fiddle for complete solution.
I have code to plot pie chart. Problem is when i zoom Pie chart it goes out of Division inside which it is placed.I searched on google and got to know there is .zoom function for D3 charts to achieve this.Can anyone help me how can i do it?
Graph should be visible in all the media like in Desktop , mobile , ipad
var canvasWidth = this.getWidth(), //width
canvasHeight = this.getHeight(), //height
outerRadius = 75,
margin = {top: 20, right: 20, bottom: 30, left: 40},//radius
color = d3.scale.category20(); //builtin range of colors
var vis = d3.select("#"+this.htmlObject)
.append("svg:svg") //create the SVG element inside the <body>
.data([data]) //associate our data with the document
.attr("width", canvasWidth) //set the width of the canvas
.attr("height", canvasHeight) //set the height of the canvas
.append("svg:g") //make a group to hold our pie chart
.attr("transform", "translate(" + 1.5*outerRadius + "," + 1.5*outerRadius + ")") // relocate center of pie to 'outerRadius,outerRadius'
.attr('transform', 'translate(' + (canvasWidth/2 - 20) + ',' + canvasHeight/2 +')');
var arc = d3.svg.arc()
.outerRadius(outerRadius);
var pie = d3.layout.pie() //this will create arc data for us given a list of values
.value(function(d) { return d.magnitude; }); // Binding each value to the pie
var arcs = vis.selectAll("g.slice")
.data(pie)
.enter()
.append("svg:g")
.attr("class", "slice"); //allow us to style things in the slices (like text)
arcs.append("svg:path")
.attr("fill", function(d, i) { return color(i); } )
.attr("d", arc);
arcs.append("svg:text")
.attr("transform", function(d) { //set the label's origin to the center of the arc
d.outerRadius = outerRadius + 50; // Set Outer Coordinate
d.innerRadius = outerRadius + 45; // Set Inner Coordinate
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle") //center the text on it's origin
.style("fill", "Purple")
.style("font", "bold 12px Arial")
.text(function(d, i) { return data[i].legendLabel; }); //get the label from our original data array
arcs.filter(function(d) { return d.endAngle - d.startAngle > .2; }).append("svg:text")
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.attr("transform", function(d) { //set the label's origin to the center of the arc
d.outerRadius = outerRadius; // Set Outer Coordinate
d.innerRadius = outerRadius/2; // Set Inner Coordinate
return "translate(" + arc.centroid(d) + ")rotate(" + angle(d) + ")";
})
.style("fill", "White")
.style("font", "bold 12px Arial")
.text(function(d) { return d.data.magnitude; });
function angle(d) {
var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
return a > 90 ? a - 180 : a;
}
I found one small code
var zoom = d3.behavior.zoom()
.x(xScale)
.on('zoom', zoomed);
You have not implemented a proper zoom function. D3 has this. Here is an example :
var zoom = d3.behavior.zoom()
.scaleExtent([1, 10])
.on("zoom", zoomed);
function zoomed() {
container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"); //the container here is the part of the SVG you wish to zoom into
}
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.right + ")")
.call(zoom); //here is the main call.
Here is an example : https://bl.ocks.org/mbostock/6123708
This is not a pie chart but it will work either way. Just where I have container, just put your pie chart container here. There are plenty of examples online for zooming in D3
I created a pie chart and it is showing great.
Only, I noticed that some text is hidden by pie slice. By looking carefully, I noticed that each text can drawn over with the next slice.
so the rendering order goes like this : slice 1, text 1, slice 2, text 2, slice 3, text 3, etc...
How can I make it so the rendering order is slice 1, slice 2, slice 3...slice n.
Then text 1, text 2, text 3...text n
and then the text will always show since it will be drawn on top of every slice of the pie.
Thanks, here is my code
function createChart(dom, newData, title) {
d3.select(dom).selectAll("*").remove();
// Define size & radius of donut pie chart
var width = 450,
height = 800,
radius = Math.min(width, height) / 2;
// Define arc colours
var colour = d3.scale.category20();
// Define arc ranges
var arcText = d3.scale.ordinal()
.rangeRoundBands([0, width], .1, .3);
// Determine size of arcs
var arc = d3.svg.arc()
.innerRadius(radius - 130)
.outerRadius(radius - 10);
// Create the donut pie chart layout
var pie = d3.layout.pie()
.value(function (d) { return d.count; })
.sort(null);
// Append SVG attributes and append g to the SVG
var mySvg = d3.select(dom).append("svg")
.attr("width", width)
.attr("height", height);
var svg = mySvg
.append("g")
.attr("transform", "translate(" + radius + "," + radius + ")");
var svgText = mySvg
.append("g")
.attr("transform", "translate(" + radius + "," + radius + ")");
// Define inner circle
svg.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", 100)
.attr("fill", "#fff") ;
// Calculate SVG paths and fill in the colours
var g = svg.selectAll(".arc")
.data(pie(newData))
.enter().append("g")
.attr("class", "arc");
// Append the path to each g
g.append("path")
.attr("d", arc)
//.attr("data-legend", function(d, i){ return parseInt(newData[i].count) + ' ' + newData[i].emote; })
.attr("fill", function(d, i) {
return colour(i);
});
// Append text labels to each arc
g.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("dy", ".35em")
.style("text-anchor", "middle")
.attr("fill", "#fff")
.text(function(d,i) { return newData[i].count > 0 ? newData[i].emote : ''; })
// Append text to the inner circle
svg.append("text")
.style("text-anchor", "middle")
.attr("fill", "#36454f")
.text(function(d) { return title; })
.style("font-size","16px")
.style("font-weight", "bold");
}
Simplest approach is to give the text labels there own g and rebind the data:
// there own g
var textG = svg.selectAll(".labels")
.data(pie(newData))
.enter().append("g")
.attr("class", "labels");
// Append text labels to each arc
textG.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("dy", ".35em")
.style("text-anchor", "middle")
.attr("fill", "#fff")
.text(function(d, i) {
return d.data.count > 0 ? d.data.emote : ''; // you can use d.data instead of indexing
});
Full example:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
</head>
<body>
<script>
var newData = [{
count: 1,
emote: "OneTwoThree"
}, {
count: 1,
emote: "FourFiveSix"
}, {
count: 1,
emote: "SevenEightNine"
}, {
count: 15,
emote: "TenElevenTwelve"
},
]
// Define size & radius of donut pie chart
var width = 450,
height = 800,
radius = Math.min(width, height) / 2;
// Define arc colours
var colour = d3.scale.category20();
// Define arc ranges
var arcText = d3.scale.ordinal()
.rangeRoundBands([0, width], .1, .3);
// Determine size of arcs
var arc = d3.svg.arc()
.innerRadius(radius - 130)
.outerRadius(radius - 10);
// Create the donut pie chart layout
var pie = d3.layout.pie()
.value(function(d) {
return d.count;
})
.sort(null);
// Append SVG attributes and append g to the SVG
var mySvg = d3.select('body').append("svg")
.attr("width", width)
.attr("height", height);
var svg = mySvg
.append("g")
.attr("transform", "translate(" + radius + "," + radius + ")");
var svgText = mySvg
.append("g")
.attr("transform", "translate(" + radius + "," + radius + ")");
// Define inner circle
svg.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", 100)
.attr("fill", "#fff");
// Calculate SVG paths and fill in the colours
var g = svg.selectAll(".arc")
.data(pie(newData))
.enter().append("g")
.attr("class", "arc");
// Append the path to each g
g.append("path")
.attr("d", arc)
//.attr("data-legend", function(d, i){ return parseInt(newData[i].count) + ' ' + newData[i].emote; })
.attr("fill", function(d, i) {
return colour(i);
});
var textG = svg.selectAll(".labels")
.data(pie(newData))
.enter().append("g")
.attr("class", "labels");
// Append text labels to each arc
textG.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("dy", ".35em")
.style("text-anchor", "middle")
.attr("fill", "#fff")
.text(function(d, i) {
return d.data.count > 0 ? d.data.emote : '';
});
</script>
</body>
</html>
http://tributary.io/inlet/10932495
I can't seem to figure out why my text labels are not showing up on my chart. Help or suggestions? Link above shows my pie chart and my code as well as my csv data.
var arvadaData = tributary.arvadaPayments
var sumPayments = d3.sum(arvadaData, function(d) {return +d.payments;});
var svg = d3.select("svg");
var width = 527,
height = 562,
radius = Math.min(width, height) / 2;
var outerRadius = width/2;
var colorScale = d3.scale.category20(); //built in range of 20 colors
var arc = d3.svg.arc() //creates <path> elements using arc data
.outerRadius(width / 2)
.innerRadius(100);
var pie = d3.layout.pie()
.sort(null)
.value(function(d){ return +d.payments });
var g = svg.selectAll("g.arc")
.data(pie(arvadaData))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + width/2 + "," + height/2 + ")");
g.append("path")
.attr("fill", function(d, i){return colorScale(i);})
.attr("d", arc);
g.append("text")
.attr("transform", function(d){ return "translate(" + arc.centroid(d) +")"; })
.attr("text-anchor", "middle")
.text(function(d){ return d[i].specialty; });
The text elements are added and positioned correctly, but their content isn't set correctly. You're passing in the data coming from the pie layout -- the original data is available under the .data member in this case. That is, the expression to set the text should be
.text(function(d){ return d.data.specialty; });
Complete demo here.