From 5387c48bd83db8f33e7a6b147b260dc43714db6c Mon Sep 17 00:00:00 2001 From: SAiTO TOSHiKi Date: Tue, 20 Dec 2016 22:01:07 +0800 Subject: [PATCH] Fix bar draw issue with `borderWidth`. (#3680) Fix bar draw issue. 1. `Chart.elements.Rectangle.draw` function supports both horizontal and vertical bar. 2. Corrected bar position at minus. 3. Adjust bar size when `borderWidth` is set. 4. Adjust bar size when `borderSkipped` is set. 5. Adjust `borderWidth` with value near 0(base). 6. Update test. --- src/controllers/controller.bar.js | 58 +-------------------------- src/elements/element.rectangle.js | 66 +++++++++++++++++++++++-------- test/element.rectangle.tests.js | 4 +- 3 files changed, 53 insertions(+), 75 deletions(-) diff --git a/src/controllers/controller.bar.js b/src/controllers/controller.bar.js index fc2f1c0c662..ecf43b19bce 100644 --- a/src/controllers/controller.bar.js +++ b/src/controllers/controller.bar.js @@ -84,6 +84,7 @@ module.exports = function(Chart) { datasetLabel: dataset.label, // Appearance + horizontal: false, base: reset ? scaleBase : me.calculateBarBase(me.index, index), width: me.calculateBarWidth(ruler), backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor), @@ -348,6 +349,7 @@ module.exports = function(Chart) { datasetLabel: dataset.label, // Appearance + horizontal: true, base: reset ? scaleBase : me.calculateBarBase(me.index, index), height: me.calculateBarHeight(ruler), backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor), @@ -355,62 +357,6 @@ module.exports = function(Chart) { borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor), borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth) }; - rectangle.draw = function() { - var ctx = this._chart.ctx; - var vm = this._view; - - var halfHeight = vm.height / 2, - topY = vm.y - halfHeight, - bottomY = vm.y + halfHeight, - right = vm.base - (vm.base - vm.x), - halfStroke = vm.borderWidth / 2; - - // 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 (vm.borderWidth) { - topY += halfStroke; - bottomY -= halfStroke; - right += halfStroke; - } - - ctx.beginPath(); - - ctx.fillStyle = vm.backgroundColor; - ctx.strokeStyle = vm.borderColor; - ctx.lineWidth = vm.borderWidth; - - // Corner points, from bottom-left to bottom-right clockwise - // | 1 2 | - // | 0 3 | - var corners = [ - [vm.base, bottomY], - [vm.base, topY], - [right, topY], - [right, bottomY] - ]; - - // Find first (starting) corner with fallback to 'bottom' - var borders = ['bottom', 'left', 'top', 'right']; - var startCorner = borders.indexOf(vm.borderSkipped, 0); - if (startCorner === -1) { - startCorner = 0; - } - - function cornerAt(cornerIndex) { - return corners[(startCorner + cornerIndex) % 4]; - } - - // Draw rectangle from 'startCorner' - ctx.moveTo.apply(ctx, cornerAt(0)); - for (var i = 1; i < 4; i++) { - ctx.lineTo.apply(ctx, cornerAt(i)); - } - - ctx.fill(); - if (vm.borderWidth) { - ctx.stroke(); - } - }; rectangle.pivot(); }, diff --git a/src/elements/element.rectangle.js b/src/elements/element.rectangle.js index 427916791ed..c3b81976140 100644 --- a/src/elements/element.rectangle.js +++ b/src/elements/element.rectangle.js @@ -53,39 +53,71 @@ module.exports = function(Chart) { draw: function() { var ctx = this._chart.ctx; var vm = this._view; - - var halfWidth = vm.width / 2, - leftX = vm.x - halfWidth, - rightX = vm.x + halfWidth, - top = vm.base - (vm.base - vm.y), - halfStroke = vm.borderWidth / 2; + var left, right, top, bottom, signX, signY, borderSkipped; + var borderWidth = vm.borderWidth; + + 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 (vm.borderWidth) { - leftX += halfStroke; - rightX -= halfStroke; - top += halfStroke; + 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 = vm.borderWidth; + ctx.lineWidth = borderWidth; // Corner points, from bottom-left to bottom-right clockwise // | 1 2 | // | 0 3 | var corners = [ - [leftX, vm.base], - [leftX, top], - [rightX, top], - [rightX, vm.base] + [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(vm.borderSkipped, 0); + var startCorner = borders.indexOf(borderSkipped, 0); if (startCorner === -1) { startCorner = 0; } @@ -104,7 +136,7 @@ module.exports = function(Chart) { } ctx.fill(); - if (vm.borderWidth) { + if (borderWidth) { ctx.stroke(); } }, diff --git a/test/element.rectangle.tests.js b/test/element.rectangle.tests.js index b833862bd6f..e72117f5a36 100644 --- a/test/element.rectangle.tests.js +++ b/test/element.rectangle.tests.js @@ -207,10 +207,10 @@ describe('Rectangle element tests', function() { args: [8.5, 0] }, { name: 'lineTo', - args: [8.5, 15.5] + args: [8.5, 14.5] // This is a minus bar. Not 15.5 }, { name: 'lineTo', - args: [11.5, 15.5] + args: [11.5, 14.5] }, { name: 'lineTo', args: [11.5, 0]