How to use Zooming with Pie in D3 charts? - javascript

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

Related

Use mouseover in pie chart and show label in d3 v3 js

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.

D3 Pie chart add scroll bar to Legends

I am facing issue for getting more than 30 legends and that legends could not be shown in vertical way nor horizontal way.
I would like to add scrollbar to only legend box so that all legends would be visible with scroll or is there any way to add legends side by side like 3 in a row something like that
I tried adding overflow property but could not work.
Below is my code
var data =[];
for(var p = 0 ;p <unique.length;p++)
{
data.push({
legendLabel:unique[p],
magnitude:uniquecount[p]
});
}
var canvasWidth = this.getWidth(), //width
canvasHeight = this.getHeight(), //height
outerRadius = 60, //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 - 50) + ',' + canvasHeight/2 +')');
vis.append("text")
.attr("x",50)
.attr("y", -110)
.attr("text-anchor", "middle")
.style("font-size", "14px")
.text("Response Code vs Count(Last 20 Mins)");
if(unique.length === 0)
{
vis.append("text")
.attr("x",50)
.attr("y", 0)
.attr("text-anchor", "middle")
.style("font-size", "12px")
.text("No Failure Transactions");
}
// This will create <path> elements for us using arc data...
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
// Select all <g> elements with class slice (there aren't any yet)
var arcs = vis.selectAll("g.slice")
// Associate the generated pie data (an array of arcs, each having startAngle,
// endAngle and value properties)
.data(pie)
// This will create <g> elements for every "extra" data element that should be associated
// with a selection. The result is creating a <g> for every object in the data array
.enter()
// Create a group to hold each slice (we will have a <path> and a <text>
// element associated with each slice)
.append("svg:g")
.attr("class", "slice"); //allow us to style things in the slices (like text)
arcs.append("svg:path")
//set the color for each slice to be chosen from the color function defined above
.attr("fill", function(d, i) { return color(i); } )
.attr("data-legend",function(d) { return d.data.legendLabel +"->" + d.data.magnitude})
//this creates the actual SVG path using the associated data (pie) with the arc drawing function
.attr("d", arc);
// Add a magnitude value to the larger arcs, translated to the arc centroid and rotated.
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(" + arc.centroid(d) + ")rotate(" + angle(d) + ")"; })
.attr("transform", function(d) { //set the label's origin to the center of the arc
//we have to make sure to set these before calling arc.centroid
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; });
legend = vis.append("g")
.attr("class","legend")
.attr("overflow-y","auto")
.attr("transform","translate(70,-50)")
.style("font-size","13px")
.call(d3.legend);
// Computes the angle of an arc, converting from radians to degrees.
function angle(d) {
var a = 180;
return a > 90 ? a - 180 : a;
}
}
else
{
var canvasWidth = this.getWidth(), //width
canvasHeight = this.getHeight(), //height
outerRadius = 75, //radius
color = d3.scale.category20(); //builtin range of colors
var viN = d3.select("#"+this.htmlObject)
.append("svg:svg") //create the SVG element inside the <body>
.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
viN.append("text")
.attr("x",200)
.attr("y", 30)
.attr("text-anchor", "middle")
.style("font-size", "14px")
.text("Response Code vs Count(Last 20 Mins)");
viN.append("text")
.attr("x",200)
.attr("y", 100)
.attr("text-anchor", "middle")
.style("font-size", "12px")
.text("No data Found");
}

D3 two donut charts on top of one another, different data sets. Javascript/HTML

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.

How to correctly draw the text over my pie chart?

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>

d3 - calculate position and rotation of element by arc edge

I'm starting playing with d3 and I want to achieve this result:
I've done this arc thing, but I don't know how to calculate position and rotation of triangle? This is my current code: (http://jsfiddle.net/spbGh/1/)
var width = 220,
height = 120;
var convertValue = function (value) {
return value * .75 * 2 * Math.PI;
}
var arc = d3.svg.arc()
.innerRadius(45)
.outerRadius(60)
.startAngle(0);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
var big_background = svg.append("path")
.datum({ endAngle: convertValue(1)})
.style("fill", "#f3f4f5")
.attr("d", arc);
var big_gain = svg.append("path")
.datum({ endAngle: convertValue(.75) })
.style("fill", "orange")
.attr("d", arc);
// HELP with this thing!!!
var triangle = svg.append('path')
.style("fill", "orange")
.attr('d', 'M 0 0 l 4 4 l -8 0 z')
You need to set the transform attribute accordingly:
.attr("transform",
"translate(" + Math.cos(convertValue(.127)-Math.PI/2)*70 + "," +
Math.sin(convertValue(.127)-Math.PI/2)*70 + ")" +
"rotate(" + ((convertValue(.127)*180/Math.PI)+180) + ")")
It becomes a bit easier if you draw the triangle the other way round. Updated jsfiddle here.

Categories

Resources