Reputation: 13
Just starting learning D3 so this should probably be a basic fix. Anyway, I'm trying to make a simple bar chart sort with a click. Can't seem to figure it out after hours of searching.
My guess is its something to do with the transition or the scales, but I of course am a novice.
Here's the code.
<script src="https://d3js.org/d3.v4.min.js"></script>
<body>
<script>
var w = 600;
var h = 250;
var dataset = [{
"namePlayer": "Player1",
"mean": 37.4375
},
{
"namePlayer": "Player2",
"mean": 13.6937
},
{
"namePlayer": "Player3",
"mean": 26.7
},
{
"namePlayer": "Player5",
"mean": 20.0804
},
{
"namePlayer": "Player6",
"mean": 27.9235
}
];
var xScale = d3.scaleBand()
.domain(dataset.map(function(d, i) {
return d.namePlayer;
}))
.range([w, 0])
.padding(0.05);
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) {
return d.mean;
})])
.range([h, 0]);
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var xAxis = d3.axisBottom()
.scale(xScale);
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d) {
return xScale(d.namePlayer);
})
.attr("width", xScale.bandwidth())
.attr("y", function(d) {
return yScale(d.mean);
})
.attr("height", function(d) {
return h - yScale(d.mean);
})
.attr("fill", function(d) {
return "rgb(0, 0, " + Math.round(d.mean * 10) + ")";
})
.on("click", function() {
sortBars();
})
var sortBars = function() {
svg.selectAll("rect")
.sort(function(a, b) {
return d3.ascending(a.mean, b.mean);
})
.transition()
.delay(function(d) {
return d.mean * 50;
})
.duration(1000)
.attr("x", function(d) {
return xScale(d.mean);
});
};
</script>
</body>
Appreciate the help!
Upvotes: 1
Views: 30
Reputation: 102194
Right now you're simply sorting a selection (and passing the wrong property to the xScale
scale).
Instead of that, you should sort the data...
dataset.sort(function(a, b) {
return d3.ascending(a.mean, b.mean);
});
... and pass it to the xScale
:
xScale.domain(dataset.map(function(d, i) {
return d.namePlayer;
}));
Then, you can use your transition.
Here is the updated code:
<script src="https://d3js.org/d3.v4.min.js"></script>
<body>
<script>
var w = 600;
var h = 250;
var dataset = [{
"namePlayer": "Player1",
"mean": 37.4375
},
{
"namePlayer": "Player2",
"mean": 13.6937
},
{
"namePlayer": "Player3",
"mean": 26.7
},
{
"namePlayer": "Player5",
"mean": 20.0804
},
{
"namePlayer": "Player6",
"mean": 27.9235
}
];
var xScale = d3.scaleBand()
.domain(dataset.map(function(d, i) {
return d.namePlayer;
}))
.range([w, 0])
.padding(0.05);
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) {
return d.mean;
})])
.range([h, 0]);
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var xAxis = d3.axisBottom()
.scale(xScale);
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d) {
return xScale(d.namePlayer);
})
.attr("width", xScale.bandwidth())
.attr("y", function(d) {
return yScale(d.mean);
})
.attr("height", function(d) {
return h - yScale(d.mean);
})
.attr("fill", function(d) {
return "rgb(0, 0, " + Math.round(d.mean * 10) + ")";
})
.on("click", function() {
sortBars();
})
var sortBars = function() {
dataset.sort(function(a, b) {
return d3.ascending(a.mean, b.mean);
});
xScale.domain(dataset.map(function(d, i) {
return d.namePlayer;
}));
svg.selectAll("rect")
.transition()
.delay(function(d) {
return d.mean * 50;
})
.duration(1000)
.attr("x", function(d) {
return xScale(d.namePlayer);
});
};
</script>
</body>
Upvotes: 1