I am making a donut chart with live cryptocurrency values I fetch via an ajax from an API. I can manage to combine the values I get from a number of calls into one json and then plot a D3 donut with those, but I have to also figure out a way to add a field into the json for each currency, which will have the amount of coins the users currently has. The point is to be able to show the user how many coins he has in value.
It would be best if the coin amounts the user has would be stored in another json, but I am so desperate anything would do really.
The difficulty for me is that D3 itself iterates over the json and plots the chart, making it hard to multiply particular values in the json with certain other numbers (the way you would multiply a circle radius by 2 to make the circles all bigger)
I will hence attach my source code. Hopefully everything is straightforward. You can find the chart here: http://codepen.io/kvyb/pen/EZGyJL?editors=0110
var a = ["https://api.cryptonator.com/api/ticker/btc-usd", "https://api.cryptonator.com/api/ticker/ltc-usd", "https://api.cryptonator.com/api/ticker/eth-usd", "https://api.cryptonator.com/api/ticker/etc-usd", "https://api.cryptonator.com/api/ticker/xmr-usd", "https://api.cryptonator.com/api/ticker/icn-usd", "https://api.cryptonator.com/api/ticker/dash-usd", "https://api.cryptonator.com/api/ticker/MAID-usd", "https://api.cryptonator.com/api/ticker/omni-usd", "https://api.cryptonator.com/api/ticker/rep-usd"];
function fetch() {
all_data = ["{\"floor\": ["];
for (index = 0; index < a.length; ++index) {
$.ajax({
url: a[index],
dataType: "json",
async: false,
error: function(data) {
console.log("--");
},
success: function(data) {
all_data += JSON.stringify(data["ticker"]) + ',';
}
})
}
};
fetch()
all_data += "]}";
var pos = all_data.lastIndexOf(',');
all_data = all_data.substring(0, pos) + "" + all_data.substring(pos + 1);
console.log(all_data)
// CHART
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var width = 960,
height = 500,
radius = Math.min(width, height) / 2;
var color = d3.scaleOrdinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var arc = d3.arc()
.outerRadius(radius - 10)
.innerRadius(radius - 150);
var pie = d3.pie()
.sort(null)
.value(function(d) {
return +d.price + 50;
});
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
data = JSON.parse(all_data);
console.log(data);
var g = svg.selectAll(".arc")
.data(pie(data.floor))
.enter().append("g")
.attr("class", "arc")
.on("mouseover", function(d) {
div.transition()
.duration(0)
.style("opacity", .9);
div .html("Price: <br>" + d.data.price + "<br/>Volume: " + d.data.volume)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(0)
.style("opacity", 0);
})
g.append("path")
.attr("d", arc)
.style("fill", function(d) {
return color(d.data.price);
});
g.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("dy", "0em")
.attr("dx", "0em")
.html(function(d) {
return d.data.base;
});
function type(d) {
d.price = +d.price;
return d;
}
How would you go about showing the number of certain coins a user has on hover?
Another approach, instead of adding values to json, would be to get all prices from the "all_data" variable, but if I try to iterate over the json I get "undefined" returned. I thought of maybe creating another json with only the prices from "all_data" and use that to find the portfolio number. Any help would be greatly appreciated.
Related
I've been having a bunch of trouble with a pie chart I've been trying to make. I finally have the outer ring working, but the inner ring only displays a few of the pieces (out ring has 3, inner ring has 6 but displays 3).
Does anyone know what might be wrong with this code? Both systems work fine on their own, but for whatever reason they don't work when I put them together.
The wedges for 20, 10 and 5 are the ones that don't display, and it happens that way every single time.
The name of the class ("arc") doesn't seem to matter, either.
function makeDonut(svg) {
var boundingBox = d3.select(svg).node().getBoundingClientRect();
var h = boundingBox.height;
var w = boundingBox.width;
/***** donut chart *****/
var data = [25, 40, 55];
// arbitrary data
var outerRadius = w/3;
var innerRadius = 3*(outerRadius/4);
var arc = d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.pie();
// order: gold, silver, bronze
var color = d3.scaleOrdinal()
.range(['#e5ce0c', '#e5e4e0', '#a4610a']);
var arcs = d3.select(svg).selectAll("g.arc")
.data(pie(data))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + (w/2) + "," + ((h-25)/2) + ")");
arcs.append("path")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc)
.attr("stroke", "white")
.style("stroke-width", "0.5px")
.on('mouseover', function(d) {
d3.select(this).attr('opacity', .7);
})
.on('mouseleave', function(d) {
d3.select(this).attr('opacity', 1);
});
arcs.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text(function(d) {
return d.value;
});
/************ piechart ************/
var dataset = [ 5, 10, 20, 45, 6, 25 ];
// arbitrary dataset
var outerRadius2 = 0.75 * (w/3);
var innerRadius2 = 0;
var arc2 = d3.arc()
.innerRadius(innerRadius2)
.outerRadius(outerRadius2);
var pie2 = d3.pie();
var color2 = d3.scaleOrdinal(d3.schemeCategory10);
var arcs2 = d3.select(svg).selectAll("g.arc")
.data(pie2(dataset))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + (w/2) + "," + ((h-25)/2) + ")");
//Draw arc paths
arcs2.append("path")
.attr("fill", function(d, i) {
return color2(i);
})
.attr("d", arc2);
arcs2.append("text")
.attr("transform", function(d) {
return "translate(" + arc2.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text(function(d) {
return d.value;
});
}
The D3 enter method creates elements in the DOM where needed so that for every item in the data array there is an appropriate element in the DOM.
For your donut chart, which you draw first, you selectAll("g.arc") - there are no g elements with the class arc, you have an empty selection. So when you use the enter method, D3 creates one element for every item in the data array. Everything chained to .enter(), without a .merge() method, only affects these entered elements.
For your pie chart, which you draw second, you selectAll("g.arc") - however, now there are three g elements with the class arc. So when you use the enter method here, the enter selection does not included elements for the first three items in the data array: they already exist. Instead these first three elements are included in the update selection.
This functionality is core to the D3 enter/update/exit cycle.
If you want to enter everything, and aren't updating or exiting data points, then you can simply use .selectAll(null) which will create an empty selection, for which an enter selection will create an element for every item in the data array.
If you wanted to modify these wedges/arcs later, you could differentiate the two, either by entering them in different g elements (eg: g1.selectAll("g.arc") and g2.selectAll("g.arc"). Alternatively, you could give them different class names based on whether pie or donut, as below:
var svg = d3.select("svg");
var boundingBox = svg.node().getBoundingClientRect();
var h = boundingBox.height;
var w = boundingBox.width;
/***** donut chart *****/
var data = [25, 40, 55];
// arbitrary data
var outerRadius = w/3;
var innerRadius = 3*(outerRadius/4);
var arc = d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.pie();
// order: gold, silver, bronze
var color = d3.scaleOrdinal()
.range(['#e5ce0c', '#e5e4e0', '#a4610a']);
var arcs = svg.selectAll("donut")
.data(pie(data))
.enter()
.append("g")
.attr("class", "donut")
.attr("transform", "translate(" + (w/2) + "," + ((h-25)/2) + ")");
arcs.append("path")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc)
.attr("stroke", "white")
.style("stroke-width", "0.5px")
.on('mouseover', function(d) {
d3.select(this).attr('opacity', .7);
})
.on('mouseleave', function(d) {
d3.select(this).attr('opacity', 1);
});
arcs.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text(function(d) {
return d.value;
});
/************ piechart ************/
var dataset = [ 5, 10, 20, 45, 6, 25 ];
// arbitrary dataset
var outerRadius2 = 0.75 * (w/3);
var innerRadius2 = 0;
var arc2 = d3.arc()
.innerRadius(innerRadius2)
.outerRadius(outerRadius2);
var pie2 = d3.pie();
var color2 = d3.scaleOrdinal(d3.schemeCategory10);
var arcs2 = svg.selectAll(".pie")
.data(pie2(dataset))
.enter()
.append("g")
.attr("class", "pie")
.attr("transform", "translate(" + (w/2) + "," + ((h-25)/2) + ")");
//Draw arc paths
arcs2.append("path")
.attr("fill", function(d, i) {
return color2(i);
})
.attr("d", arc2);
arcs2.append("text")
.attr("transform", function(d) {
return "translate(" + arc2.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text(function(d) {
return d.value;
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width=500 height=400></svg>
Not able to wrap labels of semi donut pie chart which is developed using d3 js.
I tried using CSS by giving word-wrap, max-width etc., but it's not working.
How can I warp the text labels if the labels are having more than three to fours words?
Here is my fiddle: https://jsfiddle.net/SampathPerOxide/hcvuqjt2/22/
var width = 400;
var height = 300; //this is the double because are showing just the half of the pie
var radius = Math.min(width, height) / 2;
var labelr = radius + 30; // radius for label anchor
//array of colors for the pie (in the same order as the dataset)
var color = d3.scale.ordinal()
.range(['#2b5eac', '#0dadd3', '#ffea61', '#ff917e', '#ff3e41']);
data = [{
label: 'CDU',
value: 10
},
{
label: 'SPD',
value: 15
},
{
label: 'Die Grünen',
value: 8
},
{
label: 'Die Mitte',
value: 1
},
{
label: 'Frei Wähler',
value: 3
}
];
var vis = d3.select("#chart")
.append("svg") //create the SVG element inside the <body>
.data([data]) //associate our data with the document
.attr("width", width) //set the width and height of our visualization (these will be attributes of the <svg> tag
.attr("height", height)
.append("svg:g") //make a group to hold our pie chart
.attr('transform', 'translate(' + (width / 2) + ',' + (height / 2) + ')'); //move the center of the pie chart from 0, 0 to radius, radius
var arc = d3.svg.arc() //this will create <path> elements for us using arc data
.innerRadius(79)
// .outerRadius(radius);
.outerRadius(radius - 10) // full height semi pie
//.innerRadius(0);
var pie = d3.layout.pie() //this will create arc data for us given a list of values
.startAngle(-90 * (Math.PI / 180))
.endAngle(90 * (Math.PI / 180))
.padAngle(.02) // some space between slices
.sort(null) //No! we don't want to order it by size
.value(function(d) {
return d.value;
}); //we must tell it out to access the value of each element in our data array
var arcs = vis.selectAll("g.slice") //this selects all <g> elements with class slice (there aren't any yet)
.data(pie) //associate the generated pie data (an array of arcs, each having startAngle, endAngle and value properties)
.enter() //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
.append("svg:g") //create a group to hold each slice (we will have a <path> and a <text> element associated with each slice)
.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);
}) //set the color for each slice to be chosen from the color function defined above
.attr("d", arc); //this creates the actual SVG path using the associated data (pie) with the arc drawing function
const textEl = arcs.append("svg:text")
.attr("class", "labels") //add a label to each slice
.attr("fill", "grey")
.attr("transform", function(d) {
var c = arc.centroid(d),
xp = c[0],
yp = c[1],
// pythagorean theorem for hypotenuse
hp = Math.sqrt(xp * xp + yp * yp);
return "translate(" + (xp / hp * labelr) + ',' +
(yp / hp * labelr) + ")";
})
.attr("text-anchor", "middle"); //center the text on it's origin
textEl.append('tspan')
.text(function(d, i) {
return data[i].label;
});
textEl.append('tspan')
.text(function(d, i) {
return data[i].value;
})
.attr('x', '0')
.attr('dy', '1.2em');
arcs.append("svg:text")
.attr("class", "labels")//add a label to each slice
.attr("fill", "grey")
.attr("transform", function(d) {
var c = arc.centroid(d),
xp = c[0],
yp = c[1],
// pythagorean theorem for hypotenuse
hp = Math.sqrt(xp*xp + yp*yp);
return "translate(" + (xp/hp * labelr) + ',' +
(yp/hp * labelr) + ")";
})
.attr("text-anchor", "middle") //center the text on it's origin
.text(function(d, i) { return d.data.value; })
.text(function(d, i) { return d.data.label; });
//tooltip
arcs.on("mouseover", function(d) {
d3.select("#tooltip")
.style("left", `${d3.event.clientX}px`)
.style("top", `${d3.event.clientY}px`)
.classed("hidden", false);
d3.select("#tooltip-data")
.html(`Label: ${d.data.label}<br>Value: ${d.data.value}`);
});
arcs.on("mouseout", function(d) {
d3.select("#tooltip")
.classed("hidden", true);
});
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.
I am trying to make a donut chart from data which is fetched via an API. I store the data from the API in a json variable, but otherwise my code is standard.
I understand there have been some TypeErrors due to D3.js version change, but I do not even have anything with startAngle written in the code, yet I get the error Uncaught TypeError: Cannot read property 'startAngle' of undefined.
The code with this problem is on codepen : http://codepen.io/kvyb/pen/GrYzEB/
Here is the code for reference:
var a = ["https://api.cryptonator.com/api/ticker/btc-usd", "https://api.cryptonator.com/api/ticker/ltc-usd", "https://api.cryptonator.com/api/ticker/eth-usd", "https://api.cryptonator.com/api/ticker/etc-usd","https://api.cryptonator.com/api/ticker/xmr-usd","https://api.cryptonator.com/api/ticker/icn-usd","https://api.cryptonator.com/api/ticker/dash-usd","https://api.cryptonator.com/api/ticker/MAID-usd","https://api.cryptonator.com/api/ticker/omni-usd","https://api.cryptonator.com/api/ticker/rep-usd"];
function fetch() {
all_data = ["{\"floor\": ["];
for (index = 0; index < a.length; ++index) {
$.ajax({
url : a[index],
dataType : "json",
async : false,
error : function(data){
console.log("--");
},
success : function(data) {
all_data += JSON.stringify(data["ticker"]) + ',';
}
})
}
};
fetch()
all_data += "]}";
var pos = all_data.lastIndexOf(',');
all_data = all_data.substring(0,pos) + "" + all_data.substring(pos+1);
console.log(all_data)
// CHART
var width = 960,
height = 500,
radius = Math.min(width, height) / 2;
var color = d3.scaleOrdinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var arc = d3.arc()
.outerRadius(radius - 10)
.innerRadius(radius - 70);
var pie = d3.pie()
.sort(null)
.value(function(d) { return d.population; });
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
data = JSON.parse( all_data );
var g = svg.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.base); });
g.append("text")
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.text(function(d) { return d.data.base; });
function type(d) {
d.price = +d.price;
return d;
}
The startAngle, together with endAgle, padAngle, index, value and data, are properties created by the pie generator. As you're not correctly passing your data to the pie generator, you're getting that error (undefined here refers to your data).
You have two problems to fix. First, your data variable is an object, and you have to pass an array to data(). To pass the array, instead of:
.data(pie(data))
It should be:
.data(pie(data.floor))
Second, you don't have a property named population in the objects of that array. So, change the pie generator to a property that you have in your data, as volume:
var pie = d3.pie()
.sort(null)
.value(function(d) {
return +d.volume;
});
Here is your Codepen: http://codepen.io/anon/pen/EZGyrL?editors=0010
I have a JavaScript code where the dataset is hard-coded in a variable, like this -
var dataset = [
{category: "Dept 1", measure: 0.30},
{category: "Dept 2", measure: 0.25},
{category: "Dept 4", measure: 0.15},
{category: "Dept 3", measure: 0.05},
{category: "Dept 5", measure: 0.18},
{category: "Dept 6", measure: 0.04},
{category: "Dept 7", measure: 0.03}
]
;
Now I want to use the json data which is getting returned from a php file (fetching through mysql query).
Whats the effective way to do this. does getJSON works well in this case?
Note- I am working on a pie chart in d3.js and this dataset requirement is for that chart.
EDIT -
This is how the code looks after suggested changes-
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
;
d3.json("data/mixchart.php", function(error, dataset) {
if (error) return console.warn(error);
else
{
var vis = d3.select("#pieChart")
.append("svg:svg") //create the SVG element inside the <body>
.data([dataset]) //associate our data with the document
.attr("width", width) //set the width and height of our visualization (these will be attributes of the <svg> tag
.attr("height", height)
.append("svg:g") //make a group to hold our pie chart
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")") //move the center of the pie chart from 0, 0 to radius, radius
;
var arc = d3.svg.arc() //this will create <path> elements for us using arc data
.outerRadius(outerRadius).innerRadius(innerRadius);
// for animation
var arcFinal = d3.svg.arc().innerRadius(innerRadiusFinal).outerRadius(outerRadius);
var arcFinal3 = d3.svg.arc().innerRadius(innerRadiusFinal3).outerRadius(outerRadius);
var pie = d3.layout.pie() //this will create arc data for us given a list of values
.value(function(d) { return d.measure; }); //we must tell it out to access the value of each element in our data array
var arcs = vis.selectAll("g.slice") //this selects all <g> elements with class slice (there aren't any yet)
.data(pie) //associate the generated pie data (an array of arcs, each having startAngle, endAngle and value properties)
.enter() //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
.append("svg:g") //create a group to hold each slice (we will have a <path> and a <text> element associated with each slice)
.attr("class", "slice") //allow us to style things in the slices (like text)
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.on("click", up)
;
arcs.append("svg:path")
.attr("fill", function(d, i) { return color(i); } ) //set the color for each slice to be chosen from the color function defined above
.attr("d", arc) //this creates the actual SVG path using the associated data (pie) with the arc drawing function
.append("svg:title") //mouseover title showing the figures
.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 )
;
// Add a label to the larger arcs, translated to the arc centroid and rotated.
// source: http://bl.ocks.org/1305337#index.html
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 formatAsPercentage(d.value); })
.text(function(d) { return d.data.category; })
;
// Computes the label angle of an arc, converting from radians to degrees.
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("Revenue Share 2012")
.attr("class","title")
;
}
});
function mouseover() {
d3.select(this).select("path").transition()
.duration(750)
//.attr("stroke","red")
//.attr("stroke-width", 1.5)
.attr("d", arcFinal3)
;
}
function mouseout() {
d3.select(this).select("path").transition()
.duration(750)
//.attr("stroke","blue")
//.attr("stroke-width", 1.5)
.attr("d", arcFinal)
;
}
function up(d, i) {
/* update bar chart when user selects piece of the pie chart */
//updateBarChart(dataset[i].category);
updateBarChart(d.data.category, color(i));
updateLineChart(d.data.category, color(i));
}
}
dsPieChart();
Edit 2 -
<script type="text/javascript">
/*
################ 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")
;
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
;
d3.json("data/mixchart.php", function(error,data) {
data.forEach(function(d) {
d.category =d.category;
d.measure = d.measure;
});
//if (err) return console.warn(err);
var vis = d3.select("#pieChart")
.append("svg:svg") //create the SVG element inside the <body>
.data(data) //associate our data with the document
.attr("width", width) //set the width and height of our visualization (these will be attributes of the <svg> tag
.attr("height", height)
.append("svg:g") //make a group to hold our pie chart
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")") //move the center of the pie chart from 0, 0 to radius, radius
;
var arc = d3.svg.arc() //this will create <path> elements for us using arc data
.outerRadius(outerRadius).innerRadius(innerRadius);
// for animation
var arcFinal = d3.svg.arc().innerRadius(innerRadiusFinal).outerRadius(outerRadius);
var arcFinal3 = d3.svg.arc().innerRadius(innerRadiusFinal3).outerRadius(outerRadius);
var pie = d3.layout.pie() //this will create arc data for us given a list of values
.value(function(d) { return d.measure; }); //we must tell it out to access the value of each element in our data array
var arcs = vis.selectAll("g.slice") //this selects all <g> elements with class slice (there aren't any yet)
.data(pie) //associate the generated pie data (an array of arcs, each having startAngle, endAngle and value properties)
.enter() //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
.append("svg:g") //create a group to hold each slice (we will have a <path> and a <text> element associated with each slice)
.attr("class", "slice") //allow us to style things in the slices (like text)
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.on("click", up)
;
arcs.append("svg:path")
.attr("fill", function(d, i) { return color(i); } ) //set the color for each slice to be chosen from the color function defined above
.attr("d", arc) //this creates the actual SVG path using the associated data (pie) with the arc drawing function
.append("svg:title") //mouseover title showing the figures
.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 )
;
// Add a label to the larger arcs, translated to the arc centroid and rotated.
// source: http://bl.ocks.org/1305337#index.html
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 formatAsPercentage(d.value); })
.text(function(d) { return d.data.category; })
;
// Computes the label angle of an arc, converting from radians to degrees.
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("Revenue Share 2012")
.attr("class","title")
;
function mouseover() {
d3.select(this).select("path").transition()
.duration(750)
//.attr("stroke","red")
//.attr("stroke-width", 1.5)
.attr("d", arcFinal3)
;
}
function mouseout() {
d3.select(this).select("path").transition()
.duration(750)
//.attr("stroke","blue")
//.attr("stroke-width", 1.5)
.attr("d", arcFinal)
;
}
function up(d, i) {
/* update bar chart when user selects piece of the pie chart */
//updateBarChart(dataset[i].category);
updateBarChart(d.data.category, color(i));
updateLineChart(d.data.category, color(i));
}
</script>
var dataset = [];
$.getJSON("your_php_file", function(result){
dataset = result;
});
this will work but keep in mind that your php file is returning only json... rest you can play with the options.
There are numerous ways of fetching JSON, but as you're already working with d3, d3.json would be a good way to go.
E.g.
d3.json('your/json.json', function(error, json) {
if (error) return console.warn(error);
doSomethingWithJson(json)
});
Also see the d3 API