D3 graph generate everytime access to the tab - javascript

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

Related

D3 -- Nested piechart not displaying all wedges

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>

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 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.

D3 adding donut chart within a tooltip

I'm trying to display a donut chart within a tooltip. I thought it'll be simply just adding the function name or creating the chart within .html() but that isn't the case sadly. Can anyone tell me where i'm going wrong?
Here's my code:
tooltip.select('.label').html(donutChart());
function donutChart(){
var dataset = {
hddrives: [20301672448, 9408258048, 2147483648, 21474836480, 35622912,32212254720],
};
var width = 460,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range(["#2DA7E2"]);
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 70);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var path = svg.selectAll("path")
.data(pie(dataset.hddrives))
.enter().append("path")
.attr("class", "arc")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc);
svg.append("text")
.attr("dy", ".35em")
.style("text-anchor", "middle")
.attr("class", "inside")
.text(function(d) { return 'Test'; });
}
Your function donutChart appends the <svg> to the body, not inside the tooltip.
A solution can be writing this in your .html():
.html("<h1>My Donut Chart</h1><br><svg class='myDonut'></svg>")
And then call your donutChart after that line, remembering to change your var svg:
var svg = d3.select(".myDonut")
Take care for not repeating the same variable names, even if they are inside a function (separate scope)... it can cause unnecessary confusion.

Having trouble adding text lables to pie chart using d3.js

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.

Categories

Resources