Anyone accomplish to create rounded bars (only the top of the bar, radius = 4'ish) in react-chartjs-2?
same problem need help any solution on this???
same here
Hey 馃憢
I could make this work using the solution proposed in this thread:
https://github.com/chartjs/Chart.js/issues/3072 where I needed to override the Chart.elements.Rectangle.prototype.draw.
Hope it helps! 馃槃
I was able to get a TypeScript version working with react-chart-js-2 version 2.11.1 and here's how:
BarGraph.tsx
// Imports: Helper Functions
import '../helpers/roundedBarChart';
<Bar
data={graphData}
options={{
// SET ANY RADIUS HERE
cornerRadius: 4,
}}
/>
Helper Function: RoundedBarCorners.tsx
// Imports: Dependencies
// @ts-ignore
import { Chart as ChartJS } from 'react-chartjs-2';
// TypeScript Type: Corners
type Corners = 'bottom' | 'left' | 'top' |'right' | null;
// TypeScript Type: VM
interface VM {
x: number,
y: number,
horizontal: boolean,
backgroundColor: string,
borderColor: string,
borderWidth: number,
width: number,
base: number,
borderSkipped: Corners,
};
// ChartJS 2: Rounded Corners
ChartJS.elements.Rectangle.prototype.draw = function() {
// CTX
const ctx: any = this._chart.ctx;
// VM
const vm: VM = this._view;
// Dimensions
let top: number = 0;
let bottom: number = 0;
let left: number = 0;
let right: number = 0;
let signX: number = 0;
let signY: number = 0;
let borderSkipped: Corners = null;
// let left, right, top, bottom, signX, signY, borderSkipped
let borderWidth: number = vm.borderWidth;
// Corner Radius
let cornerRadius: number = this._chart.config.options.cornerRadius;
// Straight Corners (Less Than 0)
if (cornerRadius < 0) {
cornerRadius = 0;
}
// Straight Corners (Default)
if (typeof cornerRadius == 'undefined') {
cornerRadius = 0;
}
if (!vm.horizontal) {
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';
}
// 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 should be less than bar width and bar height.
const barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
borderWidth = borderWidth > barSize? barSize: borderWidth;
const halfStroke = borderWidth / 2;
// Adjust borderWidth when bar top position is near vm.base(zero).
const borderLeft = left + (borderSkipped !== 'left' ? halfStroke * signX : 0);
const borderRight = right + (borderSkipped !== 'right' ? -halfStroke * signX : 0);
const borderTop = top + (borderSkipped !== 'top' ? halfStroke * signY : 0);
const 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: Begin Path
ctx.beginPath();
// CTX: Background Color
ctx.fillStyle = vm.backgroundColor;
// CTX: Border Color
ctx.strokeStyle = vm.borderColor;
// CTX: Line Width
ctx.lineWidth = borderWidth;
// Corner Points (Clockwise: Bottom Left To Bottom Right)
const cornerPoints: Array<Array<number>> = [
[left, bottom],
[left, top],
[right, top],
[right, bottom],
];
// Find first (starting) corner with fallback to 'bottom'
const borders: Array<Corners> = ['bottom', 'left', 'top', 'right'];
// Start Corner
let startCorner: number = borders.indexOf(borderSkipped, 0);
if (startCorner === -1) {
startCorner = 0;
}
// Corner At
function cornerAt(index: number) {
return cornerPoints[(startCorner + index) % 4];
}
// Draw rectangle from 'startCorner'
// Corner
let corner = cornerAt(0);
// CTX: Move To?
ctx.moveTo(corner[0], corner[1]);
// Generate Corners
let i: number = 1;
while (i < 4) {
// Corner
corner = cornerAt(i);
// Next Corner ID
let nextCornerId: number = i + 1;
// Assign Next Corner ID (Reset)
if(nextCornerId === 4) {
nextCornerId = 0;
}
const width: number = cornerPoints[2][0] - cornerPoints[1][0];
const height: number = cornerPoints[0][1] - cornerPoints[1][1];
const x: number = cornerPoints[1][0];
const y: number = cornerPoints[1][1];
// Radius
let radius = cornerRadius;
// Radius Height: Too Tall
if (radius > Math.abs(height) / 1.5) {
radius = Math.floor(Math.abs(height) / 1.5);
}
// Radius Width: Too Wide
else if (radius > Math.abs(width) / 1.5) {
radius = Math.floor(Math.abs(width) / 1.5);
}
// Height
if (height < 0) {
// Negative values in a standard bar chart
const x_tl: number = x;
const x_tr: number = x + width;
const y_tl: number = y + height;
const y_tr: number = y + height;
const x_bl: number = x;
const x_br: number = x + width;
const y_bl: number = y;
const y_br: number = 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 {
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);
ctx.quadraticCurveTo(x + width, y + height, x + width, y + height);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
}
}
// CTX: Fill
ctx.fill();
// Border Width
if (borderWidth) {
ctx.stroke();
}
};
I was able to get a TypeScript version working with
react-chart-js-2version2.11.1and here's how:BarGraph.tsx
// Imports: Helper Functions import '../helpers/roundedBarChart'; <Bar data={graphData} options={{ // SET ANY RADIUS HERE cornerRadius: 4, }} />Helper Function: RoundedBarCorners.tsx
// Imports: Dependencies // @ts-ignore import { Chart as ChartJS } from 'react-chartjs-2'; // TypeScript Type: Corners type Corners = 'bottom' | 'left' | 'top' |'right' | null; // TypeScript Type: VM interface VM { x: number, y: number, horizontal: boolean, backgroundColor: string, borderColor: string, borderWidth: number, width: number, base: number, borderSkipped: Corners, }; // ChartJS 2: Rounded Corners ChartJS.elements.Rectangle.prototype.draw = function() { // CTX const ctx: any = this._chart.ctx; // VM const vm: VM = this._view; // Dimensions let top: number = 0; let bottom: number = 0; let left: number = 0; let right: number = 0; let signX: number = 0; let signY: number = 0; let borderSkipped: Corners = null; // let left, right, top, bottom, signX, signY, borderSkipped let borderWidth: number = vm.borderWidth; // Corner Radius let cornerRadius: number = this._chart.config.options.cornerRadius; // Straight Corners (Less Than 0) if (cornerRadius < 0) { cornerRadius = 0; } // Straight Corners (Default) if (typeof cornerRadius == 'undefined') { cornerRadius = 0; } if (!vm.horizontal) { 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'; } // 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 should be less than bar width and bar height. const barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom)); borderWidth = borderWidth > barSize? barSize: borderWidth; const halfStroke = borderWidth / 2; // Adjust borderWidth when bar top position is near vm.base(zero). const borderLeft = left + (borderSkipped !== 'left' ? halfStroke * signX : 0); const borderRight = right + (borderSkipped !== 'right' ? -halfStroke * signX : 0); const borderTop = top + (borderSkipped !== 'top' ? halfStroke * signY : 0); const 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: Begin Path ctx.beginPath(); // CTX: Background Color ctx.fillStyle = vm.backgroundColor; // CTX: Border Color ctx.strokeStyle = vm.borderColor; // CTX: Line Width ctx.lineWidth = borderWidth; // Corner Points (Clockwise: Bottom Left To Bottom Right) const cornerPoints: Array<Array<number>> = [ [left, bottom], [left, top], [right, top], [right, bottom], ]; // Find first (starting) corner with fallback to 'bottom' const borders: Array<Corners> = ['bottom', 'left', 'top', 'right']; // Start Corner let startCorner: number = borders.indexOf(borderSkipped, 0); if (startCorner === -1) { startCorner = 0; } // Corner At function cornerAt(index: number) { return cornerPoints[(startCorner + index) % 4]; } // Draw rectangle from 'startCorner' // Corner let corner = cornerAt(0); // CTX: Move To? ctx.moveTo(corner[0], corner[1]); // Generate Corners let i: number = 1; while (i < 4) { // Corner corner = cornerAt(i); // Next Corner ID let nextCornerId: number = i + 1; // Assign Next Corner ID (Reset) if(nextCornerId === 4) { nextCornerId = 0; } const width: number = cornerPoints[2][0] - cornerPoints[1][0]; const height: number = cornerPoints[0][1] - cornerPoints[1][1]; const x: number = cornerPoints[1][0]; const y: number = cornerPoints[1][1]; // Radius let radius = cornerRadius; // Radius Height: Too Tall if (radius > Math.abs(height) / 1.5) { radius = Math.floor(Math.abs(height) / 1.5); } // Radius Width: Too Wide else if (radius > Math.abs(width) / 1.5) { radius = Math.floor(Math.abs(width) / 1.5); } // Height if (height < 0) { // Negative values in a standard bar chart const x_tl: number = x; const x_tr: number = x + width; const y_tl: number = y + height; const y_tr: number = y + height; const x_bl: number = x; const x_br: number = x + width; const y_bl: number = y; const y_br: number = 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 { 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); ctx.quadraticCurveTo(x + width, y + height, x + width, y + height); ctx.lineTo(x + radius, y + height); ctx.quadraticCurveTo(x, y + height, x, y + height); ctx.lineTo(x, y + radius); ctx.quadraticCurveTo(x, y, x + radius, y); } } // CTX: Fill ctx.fill(); // Border Width if (borderWidth) { ctx.stroke(); } };
this doesn't seem to work, I'm using the same version as yours and the charts are not even rendering and pc cpu usage gets high, although I used the https://github.com/chartjs/Chart.js/issues/3072#issuecomment-708413792 code and worked, besides editing it a bit
Most helpful comment
same problem need help any solution on this???