Reputation: 1831
I have used the pattern of reusable charts described by mike bostock. I am facing one problem.
Pie Chart functionality :-
1. When i click on a tab of pie chart, it should rotate and put the color which i clicked, on top.
Problem :-
1. When i click on first chart. The functionality is implemented but it is implemented on 2nd chart.
I think the problem is related to global declaration. But i haven't declared anything globally.
Please someone help me with this pretty basic task.
This is my js fiddle link where you can check this anamoly. https://jsfiddle.net/a0u2nk47/
<html>
<head>
<script type="text/javascript" src="d3.v4.min.js"></script>
<script type="text/javascript" src="d3-path.v1.min.js"></script>
<script type="text/javascript" src="d3-shape.v1.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<style>
body{
height: 100%;
width: 100%;
/*background-image: url("Computer.png");*/
}
p{
float:left;
}
</style>
</head>
<!-- <img src=Computer.png width="70%" height="100%"> -->
<p id="chart1"></p>
<p id="chart2"></p>
<body >
<script>
function piechart(){
var width = 400;
var height = 400;
var colors = ['red','green','blue']
var innerRadius = 40;
var outerRadius = 60;
var index = 0;
var pie = d3.pie()
.sort(null);
var arc = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius).cornerRadius(5).padAngle(0.05);
function chart(selection){
selection.each(function() {
svg = d3.select(this)
.append('svg')
.attr('width',width)
.attr('height',height)
.append('g')
.attr('transform','translate('+width/2+','+height/2+')')
path = svg.selectAll("path")
.data(pie(data))
.enter()
.append('path')
.attr('d',function(d){return arc(d)})
.style('fill',function(d,i){return colors[i]})
.style('stroke','black')
.each(function(d) { this._current = d; });
updateData = function(){
path.data(pie(data))
path.transition().duration(2000).attrTween("d", arcTween);
}
updateWidth = function(){
innerRadius = width*0.6
outerRadius = width*0.8
arc.innerRadius(innerRadius).outerRadius(outerRadius);
path.transition().duration(1000).attr('d',function(d){return arc(d)});
}
path.on("click",chart.click);
})
}
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return arc(i(t));
};
}
chart.data = function(value){
if(!arguments.length) return data;
data = value;
if(typeof updateData === 'function') updateData();
return chart;
}
chart.width = function(value){
if(!arguments.length) return width;
width = value;
if(typeof updateWidth === 'function') updateWidth();
return chart;
}
chart.click = function(value){
debugger;
index = this.__data__.index
console.log(index)
var rotate = 0-(value.startAngle + value.endAngle)/2 / Math.PI * 180;
// Transition the pie chart
svg.transition()
.attr("transform", "translate("+width/2+","+height/2+") rotate(" + rotate + ")")
.duration(1000);
}
return chart
}
data = [1,5,8];
var piechart1 = piechart().data(data);
d3.select('#chart1').call(piechart1);
var piechart2 = piechart().data(data);
d3.select('#chart2').call(piechart2);
</script>
</body>
Upvotes: 0
Views: 39
Reputation: 5670
As you're transitioning/transforming the <g>
element which is the parent of the path
s you click on, you can just use this.parentNode
to transform it.
For example, in the click
handler, change the following:
svg.transition().attr('....
to
d3.select(this.parentNode).transition().attr('...
Although I'd suggest you assign an ID to each of the charts to separate them out in case of a reusable chart logic and use this newly created ID for all other functionalities instead of depending on the global variables. For instance:
var piechart1 = piechart(1).data(data); // pass an ID here
and assign it the following way:
svg.append('g').attr('id', 'container_' + id) // assign the ID
Here's a snippet followed with a fiddle fork:
function piechart(id){
var width = 300;
var height = 300;
var colors = ['red','green','blue']
var innerRadius = 40;
var outerRadius = 60;
var index = 0;
var pie = d3.pie()
.sort(null);
var arc = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius).cornerRadius(5).padAngle(0.05);
function chart(selection){
selection.each(function() {
svg = d3.select(this)
.append('svg')
.attr('width',width)
.attr('height',height)
.append('g').attr('id', 'container_' + id)
.attr('transform','translate('+width/2+','+height/2+')')
path = svg.selectAll("path")
.data(pie(data))
.enter()
.append('path')
.attr('d',function(d){return arc(d)})
.style('fill',function(d,i){return colors[i]})
.style('stroke','black')
.each(function(d) { this._current = d; });
path.on("click",chart.click);
})
}
chart.data = function(value){
if(!arguments.length) return data;
data = value;
if(typeof updateData === 'function') updateData();
return chart;
}
chart.click = function(value){
index = this.__data__.index
var rotate = 0-(value.startAngle + value.endAngle)/2 / Math.PI * 180;
// Transition the pie chart
d3.select(this.parentNode).transition()
.attr("transform", "translate("+width/2+","+height/2+") rotate(" + rotate + ")")
.duration(1000);
}
return chart
}
data = [1,5,8];
var piechart1 = piechart(1).data(data);
d3.select('#chart1').call(piechart1);
var piechart2 = piechart(2).data(data);
d3.select('#chart2').call(piechart2);
<html>
<head>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-path.v1.min.js"></script>
<script src="https://d3js.org/d3-shape.v1.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<style>
body{
height: 100%;
width: 100%;
/*background-image: url("Computer.png");*/
}
p{
float:left;
}
</style>
</head>
<!-- <img src=Computer.png width="70%" height="100%"> -->
<p id="chart1"></p>
<p id="chart2"></p>
<body >
</body>
</html>
https://jsfiddle.net/rL96uv4g/
Hope this helps.
Upvotes: 1