Reputation: 648
I'm having an issue getting my transitions to work between datasets. I would like the numbers, rectangles and names to smoothly transition between eachother when the button is clicked, but at present they only jump.
I'm using them like this
players.select('.saves')
.transition().duration(200)
.attr('y', function(d, i) {
return i * (h / data.length);
})
.attr('width', function(d) {
return Scale(d['saves']) ;});
Is the problem with my selections?
https://jsfiddle.net/8voee4fm/1/
<button class="opts champ" value="championsleague">Champions League</button>
<button class="opts prem" value="premierleague">Premier League</button>
<div id="chart"></div>
var w = 300, h = 300;
var barHeight = 20;
var data =
championsleague = [{
"name": "Hart",
"saves": "9",
"total": "15",
}, {
"name": "Subasic",
"saves": "6",
"total": "10"
}, {
"name": "Neuer",
"saves": "5",
"total": "9"
},{
"name": "Olsen",
"saves": "9",
"total": "18"
}, ];
premierleague = [{
"name": "Hart",
"saves": "12",
"total": "27"
}, {
"name": "Forster",
"saves": "13",
"total": "22"
}, {
"name": "De Gea",
"saves": "17",
"total": "29"
}, {
"name": "Green",
"saves": "21",
"total": "39"
},];
data.forEach(function(d){
d.saves = +d.saves;
d.total = +d.total;
});
var canvas = d3.select('#chart')
.append('svg')
.attr('width', w)
.attr('height', h)
.append('g')
.attr("transform", "translate(10,30)");
var Scale = d3.scale.linear().domain([0, 39]).range([0, w]);
function updateLegend(data) {
var players = canvas
.selectAll(".player")
.data(data, function(d){
// always create a unique key for your data-binding
return d.name + d.saves + d.total;
});
var playersEnter = players
.enter()
.append("g")
.attr("class", "player");
playersEnter.append('rect')
.attr('class','total')
.style("fill", "#abcbc0")
.attr('x', 0)
.attr('height', barHeight);
playersEnter.append('text')
.attr('class','totaln')
.style("fill", "black")
.style("text-anchor", "right");
playersEnter.append('rect')
.attr('class','saves')
.style("fill", "#008c6c")
.attr('x', 0)
.attr('height', barHeight);
playersEnter.append('text')
.attr('class','savesn')
.style("text-anchor", "right")
.style("fill", "white");
playersEnter.append('text')
.attr('class','name')
.attr('x', 0);
players.select('.total').transition()
.duration(200)
.attr('y', function(d, i) {
return i * (h / data.length)
})
.attr('width', function(d) {
return Scale(d['total'])
})
.attr('height', barHeight);
players.select('.totaln').transition()
.duration(200).text(function(d) {
return d.total;
})
.attr('x', function(d) {
return Scale(d['total']) -20})
.attr('y', function(d,i) {
return i * (h / data.length ) +15
});
players.select('.saves')
.transition().duration(200)
.attr('y', function(d, i) {
return i * (h / data.length);
})
.attr('width', function(d) {
return Scale(d['saves']) ;});
players.select('.savesn')
.transition()
.duration(200).text(function(d) {
return d.saves;
})
.attr('x', function(d) {
return Scale(d['saves']) -18})
.attr('y', function(d,i) {
return i * (h / data.length ) +15
});
players.select('.name')
.transition().duration(200)
.text(function(d) {
return d.name;
})
.attr('y', function(d, i) {
return i * (h / data.length) -10
});
// remove old elements
players.exit().remove();
};
updateLegend(data);
d3.selectAll('.opts')
.on('click', function() {
var data = eval(d3.select(this).property('value'));
console.log(data)
updateLegend(data);
})
Upvotes: 3
Views: 1602
Reputation: 102218
If you want to avoid the use of eval(), you can change your handle on click event:
d3.selectAll('.opts')
.on('click', function() {
var data = eval(d3.select(this).property('value'));
console.log(data)
updateLegend(data);
})
to something like this:
d3.selectAll('.opts')
.on('click', function() {
var newdata = d3.select(this).property('value');
newdata = window[newdata];
console.log(newdata)
updateLegend(newdata);
})
(not really an answer, but I don't have enough points to comment)
Upvotes: 1
Reputation: 1998
You just have to correct one line of code:
instead of
var players = canvas
.selectAll(".player")
.data(data, function(d){
// always create a unique key for your data-binding
return d.name + d.saves + d.total;
});
you write:
var players = canvas
.selectAll(".player")
.data(data);
Now it works. The problem was the following: The DOM elements you create in the enter selection are not valid SVG elements since at least one attribute was missing (E.g. the width is missing for the rect). As a result the transition created the object (from an underspecified SVG object).
So now you have transitions for all but the initial display because of the reason described above.
Here's the working JSFiddle: https://jsfiddle.net/ee2todev/xjf0k2oy/
Upvotes: 1