Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow configuration of borderWidth as object #6047

Closed
wants to merge 16 commits into from
Closed
132 changes: 77 additions & 55 deletions src/elements/element.rectangle.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

var defaults = require('../core/core.defaults');
var Element = require('../core/core.element');
var helpers = require('../helpers/index');

var defaultColor = defaults.global.defaultColor;
var valueOrDefault = helpers.valueOrDefault;

defaults._set('global', {
elements: {
Expand Down Expand Up @@ -58,8 +60,11 @@ module.exports = Element.extend({
draw: function() {
var ctx = this._chart.ctx;
var vm = this._view;
var left, right, top, bottom, signX, signY, borderSkipped;
var borderWidth = vm.borderWidth;
var lineCount = 0;
var width = 0;
var left, right, top, bottom, signX, signY, borderSkipped;
var maxWidth, maxHeight, prevWidth, nextWidth;

if (!vm.horizontal) {
// bar
Expand All @@ -69,7 +74,7 @@ module.exports = Element.extend({
bottom = vm.base;
signX = 1;
signY = bottom > top ? 1 : -1;
borderSkipped = vm.borderSkipped || 'bottom';
borderSkipped = valueOrDefault(vm.borderSkipped, {bottom: true}) || {};
kurkle marked this conversation as resolved.
Show resolved Hide resolved
} else {
// horizontal bar
left = vm.base;
Expand All @@ -78,70 +83,87 @@ module.exports = Element.extend({
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;
}
borderSkipped = valueOrDefault(vm.borderSkipped, {left: true}) || {};
}

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;

if (!borderWidth) {
ctx.fillRect(left, bottom, right - left, top - bottom);
return;
}

function cornerAt(index) {
return corners[(startCorner + index) % 4];
if (typeof borderSkipped === 'string') {
borderSkipped = {};
borderSkipped[vm.borderSkipped] = true;
}

// Draw rectangle from 'startCorner'
var corner = cornerAt(0);
ctx.moveTo(corner[0], corner[1]);
maxWidth = Math.abs(left - right) / 2;
maxHeight = Math.abs(top - bottom) / 2;
if (!helpers.isObject(borderWidth)) {
kurkle marked this conversation as resolved.
Show resolved Hide resolved
borderWidth = {
bottom: borderSkipped.bottom ? 0 : Math.min(borderWidth, maxHeight),
left: borderSkipped.left ? 0 : Math.min(borderWidth, maxWidth),
top: borderSkipped.top ? 0 : Math.min(borderWidth, maxHeight),
right: borderSkipped.right ? 0 : Math.min(borderWidth, maxWidth)
};
} else {
borderWidth = {
bottom: Math.min(borderWidth.bottom || 0, maxHeight),
benmccann marked this conversation as resolved.
Show resolved Hide resolved
left: Math.min(borderWidth.left || 0, maxWidth),
top: Math.min(borderWidth.top || 0, maxHeight),
right: Math.min(borderWidth.right || 0, maxWidth)
};
}

for (var i = 1; i < 4; i++) {
corner = cornerAt(i);
ctx.lineTo(corner[0], corner[1]);
ctx.fillRect(
left + borderWidth.left * signX,
bottom - borderWidth.bottom * signY,
right - left - signX * (borderWidth.left + borderWidth.right),
top - bottom + signY * (borderWidth.top + borderWidth.bottom));

function drawBorder(w, x1, y1, x2, y2, x1x, y1x, x2x, y2x) {
prevWidth = width;
width = nextWidth;
nextWidth = w;

if (!width) {
return;
}

if (ctx.lineWidth !== width) {
if (lineCount) {
ctx.stroke();
ctx.beginPath();
lineCount = 0;
}
ctx.lineWidth = width;
}

x1 += x1x * signX * width / 2;
y1 += y1x * signY * width / 2;
if (prevWidth !== width) {
ctx.moveTo(x1, y1);
}
if (width === nextWidth) {
x2 = x2x === 0 ? x1 : x2 + x2x * signX * nextWidth / 2;
y2 = y2x === 0 ? y1 : y2 + y2x * signY * nextWidth / 2;
} else {
x2 = x2x === 0 ? x1 : x2 + x2x * signX * nextWidth;
y2 = y2x === 0 ? y1 : y2 + y2x * signY * nextWidth;
}
ctx.lineTo(x2, y2);
lineCount++;
}

ctx.fill();
if (borderWidth) {
ctx.beginPath();
nextWidth = borderWidth.bottom;
drawBorder(borderWidth.left, right, bottom, left, bottom, 0, -1, 1, 0);
drawBorder(borderWidth.top, left, bottom, left, top, 1, 0, 0, 1);
drawBorder(borderWidth.right, left, top, right, top, 0, 1, -1, 0);
drawBorder(borderWidth.bottom, right, top, right, bottom, -1, 0, 0, -1);
if (lineCount) {
ctx.stroke();
}
},
Expand Down
Loading