Hi there,
First thank you for your amazing library. I need to update the library 1.x to 2.0 for a client and i'm stuck on how to extend correctly my bar chart. I need to apply the same rounded effect on the bar which has been made with v1.0.2 . ChartJS syntax is quite different now.
var originalBarController = Chart.controllers.bar;
Chart.controllers.bar = Chart.controllers.bar.extend({
draw: function(ease) {
var i =0;
originalBarController.prototype.draw.apply(this, arguments);
/* write here the change to make to corners rounded */
}
});
Q1 : How can I retrieve the dataset -> bars' array from the extend function ? I only found the bar value with this.chart.chart.config.data.datasets.
Q2 : How can I perform that ?
Any advices appreciated!
JSField : http://jsfiddle.net/0dzp3jxw/
@jiboune I think this is going to be a lot easier in V2 (at least the drawing part anyway). You should only have to do:
Chart.elements.Rectangle.prototype.draw = function() {
// do drawing here including rounded options.
};
The bar will have some properties in _view which are used for drawing. If you want to add more you need to modify the bar controller updateElement method
Thank you @etimberg, I'll check this out
Closing as answered
@etimberg do you have a working example of this that you can share? In jsfiddle perhaps.
A working example would help me quite a bit as well.
thanks jedtrow @jedtrow
Any idea on how to accomplish this (rounded bars) in React with react-chartjs-2?
How to apply it only on the top of the bar using the Rounded-Bar-Charts example?
Thanks
an awsome solution is provided here. works on 2.7
https://github.com/jedtrow/Chart.js-Rounded-Bar-Charts/blob/master/demo/index.html
Any idea on how to accomplish this (rounded bars) in React with react-chartjs-2?
@mtebele
I found a way to do rounded corners on the top. All you have to do is specify radius 0 for the desired corners. If we're talking about vertical bar charts its the corners 3 & 4, in the case of the horizontal bar charts its the corners 1 & 4.
Here is the relevant code:
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
if (this._chart.config.type === 'bar') {
ctx.quadraticCurveTo(x + width, y + height, x + width - 0, y + height);
} else {
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
}
ctx.lineTo(x + radius, y + height);
if (this._chart.config.type === 'horizontalBar' || this._chart.config.type === 'bar') {
ctx.quadraticCurveTo(x, y + height, x, y + height - 0);
} else {
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
}
ctx.lineTo(x, y + radius);
if (this._chart.config.type === 'horizontalBar') {
ctx.quadraticCurveTo(x, y, x + 0, y);
} else {
ctx.quadraticCurveTo(x, y, x + radius, y);
}
Hope this helps!
@franalt where to add your code snippet?
@PrateekGoyal18 I changed the way I do this for a more effecive one.
Just add this to your HTML, below your chart.js integration:
<script src="js/Chart.roundedBarCharts.js"></script>
And create a Chart.roundedBarCharts.js file in your JS folder whit the following:
Chart.elements.Rectangle.prototype.draw` = function() {
var ctx = this._chart.ctx;
var vm = this._view;
var left, right, top, bottom, signX, signY, borderSkipped, radius;
var borderWidth = vm.borderWidth;
// If radius is less than 0 or is large enough to cause drawing errors a max
// radius is imposed. If cornerRadius is not defined set it to 0.
var cornerRadius = this._chart.config.options.cornerRadius;
if(cornerRadius < 0){ cornerRadius = 0; }
if(typeof cornerRadius == 'undefined'){ cornerRadius = 0; }
if (!vm.horizontal) {
// bar
left = vm.x - vm.width / 2;
right = vm.x + vm.width / 2;
top = vm.y;
bottom = vm.base;
signX = 1;
signY = bottom > top? 1: -1;
borderSkipped = vm.borderSkipped || 'bottom';
} else {
// horizontal bar
left = vm.base;
right = vm.x;
top = vm.y - vm.height / 2;
bottom = vm.y + vm.height / 2;
signX = right > left? 1: -1;
signY = 1;
borderSkipped = vm.borderSkipped || 'left';
}
// Canvas doesn't allow us to stroke inside the width so we can
// adjust the sizes to fit if we're setting a stroke on the line
if (borderWidth) {
// borderWidth shold be less than bar width and bar height.
var barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
borderWidth = borderWidth > barSize? barSize: borderWidth;
var halfStroke = borderWidth / 2;
// Adjust borderWidth when bar top position is near vm.base(zero).
var borderLeft = left + (borderSkipped !== 'left'? halfStroke * signX: 0);
var borderRight = right + (borderSkipped !== 'right'? -halfStroke * signX: 0);
var borderTop = top + (borderSkipped !== 'top'? halfStroke * signY: 0);
var borderBottom = bottom + (borderSkipped !== 'bottom'? -halfStroke * signY: 0);
// not become a vertical line?
if (borderLeft !== borderRight) {
top = borderTop;
bottom = borderBottom;
}
// not become a horizontal line?
if (borderTop !== borderBottom) {
left = borderLeft;
right = borderRight;
}
}
ctx.beginPath();
ctx.fillStyle = vm.backgroundColor;
ctx.strokeStyle = vm.borderColor;
ctx.lineWidth = borderWidth;
// Corner points, from bottom-left to bottom-right clockwise
// | 1 2 |
// | 0 3 |
var corners = [
[left, bottom],
[left, top],
[right, top],
[right, bottom]
];
// Find first (starting) corner with fallback to 'bottom'
var borders = ['bottom', 'left', 'top', 'right'];
var startCorner = borders.indexOf(borderSkipped, 0);
if (startCorner === -1) {
startCorner = 0;
}
function cornerAt(index) {
return corners[(startCorner + index) % 4];
}
// Draw rectangle from 'startCorner'
var corner = cornerAt(0);
ctx.moveTo(corner[0], corner[1]);
for (var i = 1; i < 4; i++) {
corner = cornerAt(i);
nextCornerId = i+1;
if(nextCornerId == 4){
nextCornerId = 0
}
nextCorner = cornerAt(nextCornerId);
width = corners[2][0] - corners[1][0];
height = corners[0][1] - corners[1][1];
x = corners[1][0];
y = corners[1][1];
var radius = cornerRadius;
if (i > 3) {
radius = 1;
}
// Fix radius being too large
if(radius > Math.abs(height)/2){
radius = Math.floor(Math.abs(height)/2);
}
if(radius > Math.abs(width)/2){
radius = Math.floor(Math.abs(width)/2);
}
if(height < 0){
// Negative values in a standard bar chart
x_tl = x; x_tr = x+width;
y_tl = y+height; y_tr = y+height;
x_bl = x; x_br = x+width;
y_bl = y; y_br = y;
// Draw
ctx.moveTo(x_bl+radius, y_bl);
ctx.lineTo(x_br-radius, y_br);
ctx.quadraticCurveTo(x_br, y_br, x_br, y_br-radius);
ctx.lineTo(x_tr, y_tr+radius);
ctx.quadraticCurveTo(x_tr, y_tr, x_tr-radius, y_tr);
ctx.lineTo(x_tl+radius, y_tl);
ctx.quadraticCurveTo(x_tl, y_tl, x_tl, y_tl+radius);
ctx.lineTo(x_bl, y_bl-radius);
ctx.quadraticCurveTo(x_bl, y_bl, x_bl+radius, y_bl);
}else if(width < 0){
// Negative values in a horizontal bar chart
x_tl = x+width; x_tr = x;
y_tl= y; y_tr = y;
x_bl = x+width; x_br = x;
y_bl = y+height; y_br = y+height;
// Draw
ctx.moveTo(x_bl+radius, y_bl);
ctx.lineTo(x_br-radius, y_br);
ctx.quadraticCurveTo(x_br, y_br, x_br, y_br-radius);
ctx.lineTo(x_tr, y_tr+radius);
ctx.quadraticCurveTo(x_tr, y_tr, x_tr-radius, y_tr);
ctx.lineTo(x_tl+radius, y_tl);
ctx.quadraticCurveTo(x_tl, y_tl, x_tl, y_tl+radius);
ctx.lineTo(x_bl, y_bl-radius);
ctx.quadraticCurveTo(x_bl, y_bl, x_bl+radius, y_bl);
} else{
//Positive Value
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
if (this._chart.config.type === 'sd') {
ctx.quadraticCurveTo(x + width, y, x + width, y + 0);
} else {
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
}
ctx.lineTo(x + width, y + height - radius);
if (this._chart.config.type === 'bar') {
ctx.quadraticCurveTo(x + width, y + height, x + width - 0, y + height);
} else {
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
}
ctx.lineTo(x + radius, y + height);
if (this._chart.config.type === 'horizontalBar' || this._chart.config.type === 'bar') {
ctx.quadraticCurveTo(x, y + height, x, y + height - 0);
} else {
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
}
ctx.lineTo(x, y + radius);
if (this._chart.config.type === 'horizontalBar') {
ctx.quadraticCurveTo(x, y, x + 0, y);
} else {
ctx.quadraticCurveTo(x, y, x + radius, y);
}
}
}
ctx.fill();
if (borderWidth) {
ctx.stroke();
}
};
Hope this helps!
@franalt Many thanks for your snippet, any ideas how adapt him to stacked bars (only style top and bottom of full bar)?
Most helpful comment
Here is a working example. CodePen
Unfortunately in the time I had available, I could not get the radius to be set from the chart config so is globally set in the extension.
Tested with Charts.js 2.5.0
Source code: Repo