I am having issues trying to build this jquery based d3.js barchart plugin.
the bars are displaced to the left, not sure why
the bars are not updating to new data.
I've tried to get the bars to animate - but not had any success.
http://jsfiddle.net/NYEaX/161/
Here is the animate bars function
animateBars: function(data){
var svg = d3.select(methods.el["selector"] + " .barchart");
var bars = svg.selectAll(".bar")
.data(data);
bars
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return methods.x(d.letter); })
.attr("width", methods.x.rangeBand())
.attr("y", function(d) { return methods.y(d.frequency); })
.attr("height", function(d) { return methods.height - methods.y(d.frequency); })
.transition()
.duration(300)
bars
.transition()
.duration(300)
bars.exit()
.transition()
.duration(300)
}
I fixed the transition for new bars in your jsfiddle. I hope it reveals the functionality of transitions:
http://jsfiddle.net/NYEaX/893/
How it works: After it sets the initial height and y value, it adds a transition to the end height and y value.
bars
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return methods.x(d.letter); })
.attr("width", methods.x.rangeBand())
.attr("y", function(d) { return methods.y(0); })
.attr("height", function(d) { return methods.height - methods.y(0); })
.transition().duration(1000)
.attr("y", function(d) { return methods.y(d.frequency); })
.attr("height", function(d) { return methods.height - methods.y(d.frequency); });
Related
I'm trying to resize a grouped bar chart with a resize() function.
function resize(){
width = parseInt(d3.select(".c_chart").style("width"), 10);
x0.rangeRound([margin.left, width-margin.right]);
x1.rangeRound([margin.left,x0.bandwidth()-margin.right])
yAxis.tickSize(width);
svg.selectAll("rect")
.attr("x", function(d) { return x1(d.key); })
.attr("width", x1.bandwidth());
svg.selectAll(".x_axis")
.call(xAxis)
.selectAll("text")
.call(wrap, x0.bandwidth());
}
When I start to resize the window, x-axis is ok but the x-position of my recent don't "follow" the ticks of my x-axis.
Then, I suspect that the problem is due to x- attribute but how can I fix that?
Here is my code: https://plnkr.co/edit/XEoM7lsBvZQmY87Wz1SP?p=preview
Add a class (gbar) to the g containing the group
svg
.append("g")
.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d) { return "translate(" + x0(d.categorie) + ",0)"; })
.attr("class", "gbar")
.selectAll("rect")
.data(function(d) { return keys.map(function(key) { return {key: key, value: d[key]}; }); })
.enter().append("rect")
.attr("x", function(d) { return x1(d.key); })
.attr("y", function(d) { return y(d.value); })
.attr("width", x1.bandwidth())
.attr("height", function(d) { return height-margin.bottom - y(d.value); })
.attr("fill", function(d) { return z(d.key); });
In the resize function update the translation
svg.selectAll(".gbar")
.attr("transform", function(d) { return "translate(" + x0(d.categorie) + ",0)"; });
and update the size of the SVG
svg
.attr("width",width)
.attr("height",height);
Don't take the margin in the x1 scale
const x1 = d3.scaleBand()
.padding(0.05)
.domain(keys)
//.rangeRound([margin.left,x0.bandwidth()-margin.right])
.rangeRound([0,x0.bandwidth()]);
// resize()
//x1.rangeRound([margin.left,x0.bandwidth()-margin.right])
x1.rangeRound([0,x0.bandwidth()])
The only thing left to fix is the y-axis grid line,........
i have a line(x-y axis) and some data points on that line. line is moving from right to left based on some fixed interval of 200ms and the data points on the line are also moving along with the line.
But the issue is that, there is some delay in the movement of circles. See the jsfiddle(scroll to the right on fiddle page to see the issue i.e. delay in circle movement)
https://jsfiddle.net/rajatmehta/tm5166e1/13/
chartBody.selectAll(".dot1")
.data(globalData, function(d){ return d.timestamp; })
.enter()
.append("circle")
.attr("class", "dot1")
.attr("r", 3)
.attr("cx", function(d) {
return x(d.timestamp);
})
.attr("cy", function(d) {
return y(d.value);
});
chartBody.selectAll(".dot2")
.data(globalDataNew, function(d){ return d.timestamp; })
.enter()
.append("circle")
.attr("class", "dot2")
.attr("r", 3)
.attr("cx", function(d) {
return x(d.timestamp);
})
.attr("cy", function(d) {
return y(d.value);
});
d3.selectAll(".dot1")
//.data(globalData)
.transition()
.duration(duration)
.ease("linear")
.attr("transform", "translate(" + String(dx) + ")");
d3.selectAll(".dot2")
//.data(globalDataNew)
.transition()
.ease("linear")
.duration(duration)
.attr("transform", "translate(" + String(dxNew) + ")");
how to prevent this delay ?
You can select dot1 and dot2 at same time and apply transition.
Currently you are selecting them and apply transition to each of them separately hence the delay
I'm trying to figure out the correct way to displays labels that will sit on top of each bar in my bar chart. I'd also like them to display a % after the number.
Here is my Plunker: https://plnkr.co/edit/FbIquWxfLjcRTg7tiX4E?p=preview
I experimented with using this code from the question found in the link below. However, I wasnt able to get it to work properly (meaning the whole chart failed to display)
Adding label on a D3 bar chart
var yTextPadding = 20;
svg.selectAll(".bartext")
.data(data)
.enter()
.append("text")
.attr("class", "bartext")
.attr("text-anchor", "top")
.attr("fill", "white")
.attr("x", function(d,i) {
return x(i)+x.rangeBand()/2;
})
.attr("y", function(d,i) {
return height-y(d)+yTextPadding;
})
.text(function(d){
return d;
});
This is the most straight forward way given your existing code:
// keep a reference to the g holding the rects
var rectG = g.append("g")
.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d) { return "translate(" + x0(d.State) + ",0)"; })
.selectAll("rect")
.data(function(d) { return keys.map(function(key) { return {key: key, value: d[key]}; }); })
.enter();
// append the rects the same way as before
rectG.append("rect")
.attr("x", function(d) { return x1(d.key); })
.attr("y", function(d) { return y(d.value); })
.attr("width", x1.bandwidth())
.attr("height", function(d) { return height - y(d.value); })
.attr("fill", function(d) { return z(d.key); });
// now add the text to the g
rectG.append("text")
.text(function(d){
return d.value + '%';
})
.attr("x", function(d) { return x1(d.key) + (x1.bandwidth()/2); })
.attr("y", function(d) { return y(d.value); })
.style("text-anchor", "middle");
Updated plunker.
I'm developing a stacked chart application.
http://jsfiddle.net/NYEaX/174/
I've placed it inside a jquery plugin to create multiple instances etc... different properties and eventually different data sources.
For now I am having problems animating the chart bars and the axis.
Animate bar code
animateBars: function(selector, data){
var w = $(selector).data("width");
var h = $(selector).data("height");
var margin = methods.getMargin(h);
methods.setDimensions(w, h, margin);
//methods.setX();
//methods.setY();
//methods.setDomain(data);
var initialHeight = 0;
//var svg = d3.select(selector + " .stackedchart");
var barholder = d3.select(selector + " .barholder");
var state = barholder.selectAll(".state")
.data(data)
.enter()
.append("g")
.attr("class", "g")
.attr("x", function(d) {
return methods.x(d.Label);
})
.attr("transform", function(d) {
return "translate(" + methods.x(d.Label) + ",0)";
});
var bar = state.selectAll("rect")
.data(function(d) {
return d.blocks;
});
// Enter
bar.enter()
.append("rect")
.attr("width", methods.x.rangeBand())
.attr("y", function(d) {
return methods.y(d.y1);
})
.attr("height", function(d) {
return methods.y(d.y0) - methods.y(d.y1);
})
.style("fill", function(d) {
return methods.color(d.name);
});
// Update
bar
.attr("y", function(d) {
return methods.y(d.y1);
})
.attr("height", function(d) {
return methods.y(d.y0) - methods.y(d.y1);
})
.transition()
.duration(500)
.attr("x", function(d) {
return methods.x(d.Label);
})
.attr("width", methods.x.rangeBand())
.attr("y", function(d) {
return methods.y(d.y1);
})
.attr("height", function(d) {
return methods.y(d.y0) - methods.y(d.y1);
});
// Exit
bar.exit()
.transition()
.duration(250)
.attr("y", function(d) {
return methods.y(d.y1);
})
.attr("height", function(d) {
return methods.y(d.y0) - methods.y(d.y1);
})
.remove();
}
One problem is that "state" is generated from the "enter()" method, so all your "bar" calls are only being executed when your "g.class" is being generated, not on update. Change this:
var state = barholder.selectAll(".state")
.data(data)
.enter()
.append("g")...
to this:
var state = barholder.selectAll(".state")
.data(data);
state.enter().append("g")...
See if that helps a bit. It doesn't seem to affect your fiddle, but you might be having problems other than d3. Try simplifying your fiddle and get the d3 stuff working by itself first.
I'm working on this bar chart application.
http://jsfiddle.net/NYEaX/166/
How do I
a) animate the bars so they grow from the bottom
b) morph the axis accordingly to the new data set
animateBars: function(data){
var svg = d3.select(methods.el["selector"] + " .barchart");
var barrects = d3.select(methods.el["selector"] + " .barrects");
var initialHeight = 0;
var bar = barrects.selectAll("rect")
.data(data);
// Enter
bar.enter()
.append("rect")
.attr("class", "bar")
.attr("y", initialHeight);
// Update
bar
.attr("height", initialHeight)
.transition()
.duration(500)
.attr("x", function(d) { return methods.x(d.letter); })
.attr("width", methods.x.rangeBand())
.attr("y", function(d) { return methods.y(d.frequency); })
.attr("height", function(d) { return methods.height - methods.y(d.frequency); })
// Exit
bar.exit()
.transition()
.duration(250)
.attr("y", initialHeight)
.attr("height", initialHeight)
.remove();
},
For the former, set the y attribute to be the max height instead of 0:
.attr("y", methods.height)
For the latter, recompute the x domain and call the axis component again:
methods.x.domain(data.map(function(d) { return d.letter; }));
svg.select("g.x").call(methods.xAxis);
Complete example here.