D3,js graph dashboard conversion to png/jpg/pdf - javascript

I have created a dashboard(a set of 3 graphs) using d3, now i want to export the set of three graphs to any of the downloadable formats in the browser.
I referenced the following post and tried to download atleast one graph:
SVG to Canvas with d3.js
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")
;
// Let's create a mock visualization
function dsPieChart(){
var dataset = [
{category: "apple", measure: 0.30},
{category: "mango", measure: 0.25},
{category: "pineapple", measure: 0.18},
{category: "orange", measure: 0.0},
{category: "peach", measure: 0.18}
]
;
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 svg = d3.select("#pie")
.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 = svg.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
svg.append("svg:text")
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text("Usage Domainwise")
.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));
updateBarStatusChart(d.data.category, color(i));
}
// Create an export button
d3.select("body")
.append("button")
.html("Export")
.on("click",svgToCanvas);
var w = 100, // or whatever your svg width is
h = 100;
// Create the export function - this will just export
// the first svg element it finds
function svgToCanvas(){
// Select the first svg element
var svg = d3.select("svg")[0][0],
img = new Image(),
serializer = new XMLSerializer(),
svgStr = serializer.serializeToString(svg);
img.src = 'data:image/svg+xml;base64,'+window.btoa(svgStr);
// You could also use the actual string without base64 encoding it:
//img.src = "data:image/svg+xml;utf8," + svgStr;
var canvas = document.createElement("canvas");
document.body.appendChild(canvas);
canvas.width = w;
canvas.height = h;
canvas.getContext("2d").drawImage(img,0,0,w,h);
// Now save as png or whatever
//var myCanvas = document.getElementsByTagName("canvas")[0];
document.write('<img src="'+canvas[0].toDataURL("image/png")+'"/>');
};
}
dsPieChart();
#pie {
position:absolute;
top:50px;
left:10px;
width:400px;
height: 400px;
}
<head>
<script src="https://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<div>
<div id="pie"></div>
</div>
</body>
When i click on the export option its not able to recognise my canvas elemt i tried various options available online but to no use.
Soebody please let me know how to do it
What i want is when i cklick on export i want it to download my graph as a image

you missed image.onLoad function
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")
;
// Let's create a mock visualization
function dsPieChart(){
var dataset = [
{category: "apple", measure: 0.30},
{category: "mango", measure: 0.25},
{category: "pineapple", measure: 0.18},
{category: "orange", measure: 0.0},
{category: "peach", measure: 0.18}
]
;
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 svg = d3.select("#pie")
.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 = svg.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
svg.append("svg:text")
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text("Usage Domainwise")
.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));
updateBarStatusChart(d.data.category, color(i));
}
// Create an export button
d3.select("body")
.append("button")
.html("Export")
.on("click",svgToCanvas);
var w = 100, // or whatever your svg width is
h = 100;
// Create the export function - this will just export
// the first svg element it finds
function svgToCanvas(){
// Select the first svg element
debugger;
var svg = d3.select("svg")[0][0],
img = new Image(),
serializer = new XMLSerializer(),
svgStr = serializer.serializeToString(svg);
data = 'data:image/svg+xml;base64,'+window.btoa(svgStr);
var canvas = document.createElement("canvas");
canvas.width = 400;
canvas.height = 400;
context = canvas.getContext("2d");
img.src = data;
img.onload = function() {
context.drawImage(img, 0, 0);
var canvasdata = canvas.toDataURL("image/png");
var pngimg = '<img src="'+canvasdata+'">';
var a = document.createElement("a");
a.download = "sample.png";
a.href = canvasdata;
a.click();
};
};
}
dsPieChart();
#pie {
position:absolute;
top:50px;
left:10px;
width:400px;
height: 400px;
}
<script src="https://d3js.org/d3.v3.min.js"></script>
<div>
<div id="pie"></div>
</div>

Related

How can I create a doughnut chart with rounded edges only on one end of each segment?

I'm trying to build a doughnut chart with rounded edges only on one side. My problem is that I have both sided rounded and not just on the one side. Also can't figure out how to do more foreground arcs not just one.
const tau = 2 * Math.PI; // http://tauday.com/tau-manifesto
const arc = d3.arc()
.innerRadius(80)
.outerRadius(100)
.startAngle(0)
.cornerRadius(15);
const svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
Background arc, but I'm not sure if this is even needed?
const background = g.append("path")
.datum({endAngle: tau})
.style("fill", "#ddd")
.attr("d", arc);
const data = [ .51];
const c = d3.scaleThreshold()
.domain([.200,.205,.300,.310, .501, 1])
.range(["green","#ddd", "orange","#ddd", "red"]);
Const pie = d3.pie()
.sort(null)
.value(function(d) {
return d;
});
Only have one foreground, but need to be able to have multiple:
const foreground = g.selectAll('.arc')
.data(pie(data))
.enter()
.append("path")
.attr("class", "arc")
.datum({endAngle: 3.8})
.style("fill", function(d) {
return c(d.value);
})
.attr("d", arc)
What am I doing wrong?
var tau = 2 * Math.PI; // http://tauday.com/tau-manifesto
// An arc function with all values bound except the endAngle. So, to compute an
// SVG path string for a given angle, we pass an object with an endAngle
// property to the `arc` function, and it will return the corresponding string.
var arc = d3.arc()
.innerRadius(80)
.outerRadius(100)
.startAngle(0)
.cornerRadius(15);
// Get the SVG container, and apply a transform such that the origin is the
// center of the canvas. This way, we don’t need to position arcs individually.
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
// Add the background arc, from 0 to 100% (tau).
var background = g.append("path")
.datum({endAngle: tau})
.style("fill", "#ddd")
.attr("d", arc);
var data = [ .51];
var c = d3.scaleThreshold()
.domain([.200,.205,.300,.310, .501, 1])
.range(["green","#ddd", "orange","#ddd", "red"]);
var pie = d3.pie()
.sort(null)
.value(function(d) {
return d;
});
// Add the foreground arc in orange, currently showing 12.7%.
var foreground = g.selectAll('.arc')
.data(pie(data))
.enter()
.append("path")
.attr("class", "arc")
.datum({endAngle: 3.8})
.style("fill", function(d) {
return c(d.value);
})
.attr("d", arc)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="960" height="500"></svg>
The documentation states, that the corner radius is applied to both ends of the arc. Additionally, you want the arcs to overlap, which is also not the case.
You can add the one-sided rounded corners the following way:
Use arcs arc with no corner radius for the data.
Add additional path objects corner just for the rounded corner. These need to be shifted to the end of each arc.
Since corner has rounded corners on both sides, add a clipPath that clips half of this arc. The clipPath contains a path for every corner. This is essential for arcs smaller than two times the length of the rounded corners.
raise all elements of corner to the front and then sort them descending by index, so that they overlap the right way.
const arc = d3.arc()
.innerRadius(50)
.outerRadius(70);
const arc_corner = d3.arc()
.innerRadius(50)
.outerRadius(70)
.cornerRadius(10);
const svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
const clipPath = g.append("clipPath")
.attr("id", "clip_corners");
const c = d3.scaleQuantile()
.range(["#f7fcf0","#e0f3db","#ccebc5","#a8ddb5","#7bccc4","#4eb3d3","#2b8cbe","#08589e"]);
const pie = d3.pie().value(d => d);
function render(values) {
c.domain(values);
const arcs = pie(values);
const corners = pie(values).map(d => {
d.startAngle = d.endAngle - 0.2;
d.endAngle = d.endAngle + 0.2;
return d;
});
const clip = pie(values).map(d => {
d.startAngle = d.endAngle - 0.01;
d.endAngle = d.endAngle + 0.2;
return d;
});
g.selectAll(".arc")
.data(arcs)
.join("path")
.attr("class", "arc")
.style("fill", d => c(d.value))
.attr("d", arc);
clipPath.selectAll("path")
.data(clip)
.join("path")
.attr("d", arc);
g.selectAll(".corner")
.data(corners)
.join("path")
.raise()
.attr("class", "corner")
.attr("clip-path", "url(#clip_corner)")
.style("fill", d => c(d.value))
.attr("d", arc_corner)
.sort((a, b) => b.index - a.index);
}
function randomData() {
const num = Math.ceil(8 * Math.random()) + 2;
const values = Array(num).fill(0).map(d => Math.random());
render(values);
}
d3.select("#random_data")
.on("click", randomData);
randomData();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.3.0/d3.min.js"></script>
<button id="random_data">
Random data
</button>
<svg width="150" height="150"></svg>
I changed the dependency to the current version of d3.

D3Js v3: Path not showing up on Node Elements

With Javascript Im generating HTML-Code with a SVG in it. I want to display a a donut chart in it then. Im able to draw the chart on a static HTML-Element. However, when I try to display it in my JavaScript-generated node element the path is not showing up, but I can see the text. What am I missing here?
https://jsfiddle.net/fuL5doja/46/
function createNodes(){
var parent = document.getElementById('chart');
var child = document.createElement('div');
child.classList.add('childContainer');
parent.appendChild(child);
var svg = document.createElement('svg');
svg.id = 'donut';
child.appendChild(svg);
}
function donutChart(){
// set the dimensions and margins of the graph
var width = 30
height = 30
margin = 0
// The radius of the pieplot is half the width or half the height (smallest one). I subtract a bit of margin.
var radius = 30
// append the svg object to the div called 'my_dataviz'
var svg = d3.select('#donut')
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
// Create dummy data
var dataDummy = {a: 70, b:30}
// set the color scale
var color = d3.scale.ordinal()
.domain(dataDummy)
.range(["#bebfc2", "#8FB91C"])
// Compute the position of each group on the pie:
var pie = d3.layout.pie()
.value(function(d) {return d.value; })
var data_ready = pie(d3.entries(dataDummy))
// Build the pie chart: Basically, each part of the pie is a path that we build using the arc function.
svg.selectAll('whatever')
.data(data_ready)
.enter()
.append('path')
.attr('d', d3.svg.arc()
.innerRadius(5) // This is the size of the donut hole
.outerRadius(radius)
)
.attr('fill', function(d){ return(color(d.data.key)) })
.style("opacity", 0.7)
svg.append("text")
.attr("x", -12) // space legend
.attr("y", 2)
.attr("class", "donutText")
.text('30%');
}
function donutChart2(){
// set the dimensions and margins of the graph
var width = 30
height = 30
margin = 0
// The radius of the pieplot is half the width or half the height (smallest one). I subtract a bit of margin.
var radius = 30
// append the svg object to the div called 'my_dataviz'
var svg = d3.select('#test')
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
// Create dummy data
var dataDummy = {a: 70, b:30}
// set the color scale
var color = d3.scale.ordinal()
.domain(dataDummy)
.range(["#bebfc2", "#8FB91C"])
// Compute the position of each group on the pie:
var pie = d3.layout.pie()
.value(function(d) {return d.value; })
var data_ready = pie(d3.entries(dataDummy))
// Build the pie chart: Basically, each part of the pie is a path that we build using the arc function.
svg.selectAll('whatever')
.data(data_ready)
.enter()
.append('path')
.attr('d', d3.svg.arc()
.innerRadius(5) // This is the size of the donut hole
.outerRadius(radius)
)
.attr('fill', function(d){ return(color(d.data.key)) })
.style("opacity", 0.7)
svg.append("text")
.attr("x", -12) // space legend
.attr("y", 2)
.attr("class", "donutText")
.text('30%');
}
createNodes();
donutChart();
donutChart2();
.childContainer {
width: 200px;
height: 100px;
border: 1px solid black;
}
#mySvg {
}
<div id="chart"></div>
<svg id="test"></svg>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js" integrity="sha512-qTXRIMyZIFb8iQcfjXWCO8+M5Tbc38Qi5WzdPOYZHIlZpzBHG3L3by84BBBOiRGiEb7KKtAOAs5qYdUiZiQNNQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
You need to create the svg element with svg namespace uri for it to support path when creating directly with JavaScript:
var svg = document.createElementNS('http://www.w3.org/2000/svg','svg');
Instead of just the typical
var svg = document.createElement('svg');
Alternatively, you could use D3 to append the svg, which will make sure it's correctly namespaced!
d3.select(child).append('svg').attr('id', 'donut');

Wrap labels in semi donut pie chart using d3 js

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);
});

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");
}

Replacing fixed json variable with a json value returned from a php file

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

Categories

Resources