Skip to content

Commit

Permalink
Fix for chartjs#3293
Browse files Browse the repository at this point in the history
  • Loading branch information
bokysan committed May 17, 2017
1 parent 20452dd commit b615e1c
Showing 1 changed file with 120 additions and 52 deletions.
172 changes: 120 additions & 52 deletions src/elements/element.rectangle.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,106 @@ module.exports = function(Chart) {
}

Chart.elements.Rectangle = Chart.Element.extend({
draw: function() {
getBorderWidth: function(top, right, bottom, left) {
// Get calculated border width
var vm = this._view;
// borderWidth should be less than bar width and bar height.
// ..,maximum border width for left-right borders
var barSizeLeftRight = Math.abs(left - right);
// ...maximum border width for top-bottom borders
var barSizeTopBottom = Math.abs(top - bottom);

function ceiling(val, max) {
return val > max ? max : val;
}

// Like CSS:
// - one border to rule them all
// - top-bottom + left-right
// - top + right + bottom + left
return !vm.borderWidth ? [] :
vm.borderWidth instanceof Array && vm.borderWidth.length === 1 ? {
top: ceiling(vm.borderWidth[0], barSizeTopBottom),
right: ceiling(vm.borderWidth[0], barSizeLeftRight),
bottom: ceiling(vm.borderWidth[0], barSizeTopBottom),
left: ceiling(vm.borderWidth[0], barSizeLeftRight)
} :
vm.borderWidth instanceof Array && vm.borderWidth.length === 2 ? {
top: ceiling(vm.borderWidth[0], barSizeTopBottom),
right: ceiling(vm.borderWidth[1], barSizeLeftRight),
bottom: ceiling(vm.borderWidth[0], barSizeTopBottom),
left: ceiling(vm.borderWidth[1], barSizeLeftRight)
} :
vm.borderWidth instanceof Array ? {
top: ceiling(vm.borderWidth[0], barSizeTopBottom),
right: ceiling(vm.borderWidth[1], barSizeLeftRight),
bottom: ceiling(vm.borderWidth[2], barSizeTopBottom),
left: ceiling(vm.borderWidth[3], barSizeLeftRight)
} :
{
top: ceiling(vm.borderWidth, barSizeTopBottom),
right: ceiling(vm.borderWidth, barSizeLeftRight),
bottom: ceiling(vm.borderWidth, barSizeTopBottom),
left: ceiling(vm.borderWidth, barSizeLeftRight)
};
},
drawShape: function(borders) {
// Draw the inside shape...
var ctx = this._chart.ctx;
var vm = this._view;
var left, right, top, bottom, signX, signY, borderSkipped;
var borderWidth = vm.borderWidth;

ctx.beginPath();
ctx.fillStyle = vm.backgroundColor;
ctx.strokeStyle = 'rgba(0,0,0,0)';
ctx.lineWidth = 0;
ctx.moveTo(borders.bottom[0][0], borders.bottom[0][1]);
for (var i in borders) {
if (borders.hasOwnProperty(i)) {
ctx.lineTo(borders[i][1][0], borders[i][1][1]);
}
}
ctx.lineTo(borders.bottom[0][0], borders.bottom[0][1]);
ctx.fill();
},
adjustBorders: function(borders, borderWidth, borderSkipped) {
// Make sure border lengths are adjusted for border width.
if (!borderSkipped.includes('top') && borderWidth.top > 0) {
borders.left = [[borders.left[0][0], borders.left[0][1] - borderWidth.top/2], borders.left[1]];
borders.right = [borders.right[0], [borders.right[1][0], borders.right[1][1] - borderWidth.top/2]];
}
if (!borderSkipped.includes('bottom') && borderWidth.bottom > 0) {
borders.left = [borders.left[0], [borders.left[1][0], borders.left[1][1] + borderWidth.bottom/2]];
borders.right = [[borders.right[0][0], borders.right[0][1] + borderWidth.bottom/2], borders.right[1]];
}
},
drawBorders: function(borders, borderWidth, borderSkipped) {
// Draw the borders. Since canvas doesn't allow drawing the borders with
// different widths, draw each line individually.
var ctx = this._chart.ctx;
var vm = this._view;

ctx.strokeStyle = vm.borderColor;
for (var i in borders) {
if (borders.hasOwnProperty(i)) {
var border = borders[i];
ctx.lineWidth = borderWidth[i];
if (borderSkipped.includes(i) || !ctx.lineWidth || ctx.lineWidth === 0) {
// Skip drawing the border
continue;
}
ctx.beginPath();
ctx.moveTo(border[0][0], border[0][1]);
ctx.lineTo(border[1][0], border[1][1]);
ctx.stroke();
}
}
},
draw: function() {
var vm = this._view;
var left, right, top, bottom, signX, signY;

// Define which borders will be skipped. Esentially the same as setting borderWidth to 0
var borderSkipped = !vm.borderSkipped ? [] : vm.borderSkipped instanceof Array ? vm.borderSkipped : [vm.borderSkipped];

if (!vm.horizontal) {
// bar
Expand All @@ -64,7 +159,9 @@ module.exports = function(Chart) {
bottom = vm.base;
signX = 1;
signY = bottom > top? 1: -1;
borderSkipped = vm.borderSkipped || 'bottom';
if (borderSkipped.length===0) {
borderSkipped = ['bottom'];
}
} else {
// horizontal bar
left = vm.base;
Expand All @@ -73,21 +170,21 @@ module.exports = function(Chart) {
bottom = vm.y + vm.height / 2;
signX = right > left? 1: -1;
signY = 1;
borderSkipped = vm.borderSkipped || 'left';
if (borderSkipped.length===0) {
borderSkipped = ['left'];
}
}

var borderWidth = this.getBorderWidth(top, right, bottom, 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;
if (borderWidth.length > 0) {
// 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);
var borderLeft = left + (!borderSkipped.includes('left') ? (borderWidth.left / 2) * signX : 0);
var borderRight = right + (!borderSkipped.includes('right') ? (-borderWidth.right / 2) * signX : 0);
var borderTop = top + (!borderSkipped.includes('top') ? (borderWidth.top / 2) * signY : 0);
var borderBottom = bottom + (!borderSkipped.includes('bottom') ? (-borderWidth.bottom / 2) * signY : 0);
// not become a vertical line?
if (borderLeft !== borderRight) {
top = borderTop;
Expand All @@ -100,45 +197,16 @@ module.exports = function(Chart) {
}
}

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);
ctx.lineTo(corner[0], corner[1]);
}
var borders = {
bottom: [[left, bottom], [right, bottom]],
right: [[right, bottom], [right, top]],
top: [[right, top], [left, top]],
left: [[left, top], [left, bottom]],
};

ctx.fill();
if (borderWidth) {
ctx.stroke();
}
this.drawShape(borders);
this.adjustBorders(borders, borderWidth, borderSkipped);
this.drawBorders(borders, borderWidth, borderSkipped);
},
height: function() {
var vm = this._view;
Expand Down

0 comments on commit b615e1c

Please sign in to comment.