From 52e174cc6e2c97e96dfa8f1e02085e1bba5de850 Mon Sep 17 00:00:00 2001 From: kurkle Date: Thu, 18 Apr 2019 16:06:27 +0300 Subject: [PATCH 1/6] Fix arc border with circumference over 2*PI --- src/elements/element.arc.js | 6 ++++- .../doughnut-circumference-over-2pi.json | 24 ++++++++++++++++++ .../doughnut-circumference-over-2pi.png | Bin 0 -> 23064 bytes 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/controller.doughnut/doughnut-circumference-over-2pi.json create mode 100644 test/fixtures/controller.doughnut/doughnut-circumference-over-2pi.png diff --git a/src/elements/element.arc.js b/src/elements/element.arc.js index 1d5f9aede4d..202d3faccbf 100644 --- a/src/elements/element.arc.js +++ b/src/elements/element.arc.js @@ -30,7 +30,7 @@ module.exports = Element.extend({ if (vm) { var pointRelativePosition = helpers.getAngleFromPoint(vm, {x: chartX, y: chartY}); - var angle = pointRelativePosition.angle; + var angle = pointRelativePosition.angle; var distance = pointRelativePosition.distance; // Sanitise angle range @@ -89,6 +89,10 @@ module.exports = Element.extend({ var pixelMargin = (vm.borderAlign === 'inner') ? 0.33 : 0; var angleMargin; + if (vm.circumference > Math.PI * 2) { + sA += (eA - sA) % (Math.PI * 2); + } + ctx.save(); ctx.beginPath(); diff --git a/test/fixtures/controller.doughnut/doughnut-circumference-over-2pi.json b/test/fixtures/controller.doughnut/doughnut-circumference-over-2pi.json new file mode 100644 index 00000000000..e2c42751740 --- /dev/null +++ b/test/fixtures/controller.doughnut/doughnut-circumference-over-2pi.json @@ -0,0 +1,24 @@ +{ + "config": { + "type": "doughnut", + "data": { + "labels": ["A"], + "datasets": [{ + "data": [100], + "backgroundColor": [ + "rgba(153, 102, 255, 0.8)" + ], + "borderWidth": 20, + "borderColor": [ + "rgb(153, 102, 255)" + ] + }] + }, + "options": { + "circumference": 7, + "responsive": false, + "legend": false, + "title": false + } + } +} diff --git a/test/fixtures/controller.doughnut/doughnut-circumference-over-2pi.png b/test/fixtures/controller.doughnut/doughnut-circumference-over-2pi.png new file mode 100644 index 0000000000000000000000000000000000000000..6eaf8bccc6940ab077052796393a1a86b6976f20 GIT binary patch literal 23064 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 z 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 Date: Thu, 18 Apr 2019 22:49:48 +0300 Subject: [PATCH 2/6] Fill overlapping area, refactor --- src/elements/element.arc.js | 72 +++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/src/elements/element.arc.js b/src/elements/element.arc.js index 202d3faccbf..366b6a8ceed 100644 --- a/src/elements/element.arc.js +++ b/src/elements/element.arc.js @@ -15,6 +15,30 @@ defaults._set('global', { } }); +function pathArc(ctx, x, y, innerRadius, outerRadius, startAngle, endAngle) { + ctx.beginPath(); + ctx.arc(x, y, outerRadius, startAngle, endAngle); + ctx.arc(x, y, innerRadius, endAngle, startAngle, true); + ctx.closePath(); +} + +function clipArc(ctx, vm, startAngle, endAngle, pixelMargin) { + var angleMargin = pixelMargin / vm.outerRadius; + + // Draw an inner border by cliping the arc and drawing a double-width border + // Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders + ctx.beginPath(); + ctx.arc(vm.x, vm.y, vm.outerRadius, startAngle - angleMargin, endAngle + angleMargin); + if (vm.innerRadius > pixelMargin) { + angleMargin = pixelMargin / vm.innerRadius; + ctx.arc(vm.x, vm.y, vm.innerRadius - pixelMargin, endAngle + angleMargin, startAngle - angleMargin, true); + } else { + ctx.arc(vm.x, vm.y, pixelMargin, endAngle + Math.PI / 2, startAngle - Math.PI / 2); + } + ctx.closePath(); + ctx.clip(); +} + module.exports = Element.extend({ inLabelRange: function(mouseX) { var vm = this._view; @@ -84,45 +108,33 @@ module.exports = Element.extend({ draw: function() { var ctx = this._chart.ctx; var vm = this._view; - var sA = vm.startAngle; - var eA = vm.endAngle; + var startAngle = vm.startAngle; + var endAngle = vm.endAngle; var pixelMargin = (vm.borderAlign === 'inner') ? 0.33 : 0; - var angleMargin; - - if (vm.circumference > Math.PI * 2) { - sA += (eA - sA) % (Math.PI * 2); - } + var outerRadius = Math.max(vm.outerRadius - pixelMargin, 0); + var innerRadius = vm.innerRadius; + var x = vm.x; + var y = vm.y; + var tA; ctx.save(); - ctx.beginPath(); - ctx.arc(vm.x, vm.y, Math.max(vm.outerRadius - pixelMargin, 0), sA, eA); - ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true); - ctx.closePath(); - ctx.fillStyle = vm.backgroundColor; + + if (vm.circumference > Math.PI * 2) { + tA = startAngle; + startAngle += (endAngle - startAngle) % (Math.PI * 2); + pathArc(ctx, x, y, innerRadius, outerRadius, tA, startAngle); + ctx.fill(); + } + + pathArc(ctx, x, y, innerRadius, outerRadius, startAngle, endAngle); ctx.fill(); if (vm.borderWidth) { if (vm.borderAlign === 'inner') { - // Draw an inner border by cliping the arc and drawing a double-width border - // Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders - ctx.beginPath(); - angleMargin = pixelMargin / vm.outerRadius; - ctx.arc(vm.x, vm.y, vm.outerRadius, sA - angleMargin, eA + angleMargin); - if (vm.innerRadius > pixelMargin) { - angleMargin = pixelMargin / vm.innerRadius; - ctx.arc(vm.x, vm.y, vm.innerRadius - pixelMargin, eA + angleMargin, sA - angleMargin, true); - } else { - ctx.arc(vm.x, vm.y, pixelMargin, eA + Math.PI / 2, sA - Math.PI / 2); - } - ctx.closePath(); - ctx.clip(); - - ctx.beginPath(); - ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA); - ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true); - ctx.closePath(); + clipArc(ctx, vm, startAngle, endAngle, pixelMargin); + pathArc(ctx, x, y, innerRadius, vm.outerRadius, startAngle, endAngle); ctx.lineWidth = vm.borderWidth * 2; ctx.lineJoin = 'round'; From 0d9a902b7502fc2ec833a3718871c405cfd33521 Mon Sep 17 00:00:00 2001 From: kurkle Date: Thu, 18 Apr 2019 23:14:09 +0300 Subject: [PATCH 3/6] Remove legacy tests, please CC --- src/elements/element.arc.js | 32 ++++- test/specs/element.arc.tests.js | 210 -------------------------------- 2 files changed, 26 insertions(+), 216 deletions(-) diff --git a/src/elements/element.arc.js b/src/elements/element.arc.js index 366b6a8ceed..7acf5cae6a1 100644 --- a/src/elements/element.arc.js +++ b/src/elements/element.arc.js @@ -15,14 +15,22 @@ defaults._set('global', { } }); -function pathArc(ctx, x, y, innerRadius, outerRadius, startAngle, endAngle) { +function pathArc(ctx, x, y, args) { + var innerRadius = args.innerRadius; + var outerRadius = args.outerRadius; + var startAngle = args.startAngle; + var endAngle = args.endAngle; + ctx.beginPath(); ctx.arc(x, y, outerRadius, startAngle, endAngle); ctx.arc(x, y, innerRadius, endAngle, startAngle, true); ctx.closePath(); } -function clipArc(ctx, vm, startAngle, endAngle, pixelMargin) { +function clipArc(ctx, vm, args) { + var startAngle = args.startAngle; + var endAngle = args.endAngle; + var pixelMargin = args.pixelMargin; var angleMargin = pixelMargin / vm.outerRadius; // Draw an inner border by cliping the arc and drawing a double-width border @@ -124,17 +132,29 @@ module.exports = Element.extend({ if (vm.circumference > Math.PI * 2) { tA = startAngle; startAngle += (endAngle - startAngle) % (Math.PI * 2); - pathArc(ctx, x, y, innerRadius, outerRadius, tA, startAngle); + pathArc(ctx, x, y, { + innerRadius: innerRadius, outerRadius: outerRadius, + startAngle: tA, endAngle: startAngle + }); ctx.fill(); } - pathArc(ctx, x, y, innerRadius, outerRadius, startAngle, endAngle); + pathArc(ctx, x, y, { + innerRadius: innerRadius, outerRadius: outerRadius, + startAngle: startAngle, endAngle: endAngle + }); ctx.fill(); if (vm.borderWidth) { if (vm.borderAlign === 'inner') { - clipArc(ctx, vm, startAngle, endAngle, pixelMargin); - pathArc(ctx, x, y, innerRadius, vm.outerRadius, startAngle, endAngle); + clipArc(ctx, vm, { + startAngle: startAngle, endAngle: endAngle, + pixelMargin: pixelMargin + }); + pathArc(ctx, x, y, { + innerRadius: innerRadius, outerRadius: vm.outerRadius, + startAngle: startAngle, endAngle: endAngle + }); ctx.lineWidth = vm.borderWidth * 2; ctx.lineJoin = 'round'; diff --git a/test/specs/element.arc.tests.js b/test/specs/element.arc.tests.js index dd373643519..40d52533d5e 100644 --- a/test/specs/element.arc.tests.js +++ b/test/specs/element.arc.tests.js @@ -99,214 +99,4 @@ describe('Arc element tests', function() { expect(center.x).toBeCloseTo(0.5, 6); expect(center.y).toBeCloseTo(0.5, 6); }); - - it ('should draw correctly with no border', function() { - var mockContext = window.createMockContext(); - var arc = new Chart.elements.Arc({ - _datasetIndex: 2, - _index: 1, - _chart: { - ctx: mockContext, - } - }); - - // Mock out the view as if the controller put it there - arc._view = { - startAngle: 0, - endAngle: Math.PI / 2, - x: 10, - y: 5, - innerRadius: 1, - outerRadius: 3, - - backgroundColor: 'rgb(0, 0, 255)', - borderColor: 'rgb(255, 0, 0)', - }; - - arc.draw(); - - expect(mockContext.getCalls()).toEqual([{ - name: 'save', - args: [] - }, { - name: 'beginPath', - args: [] - }, { - name: 'arc', - args: [10, 5, 3, 0, Math.PI / 2] - }, { - name: 'arc', - args: [10, 5, 1, Math.PI / 2, 0, true] - }, { - name: 'closePath', - args: [] - }, { - name: 'setFillStyle', - args: ['rgb(0, 0, 255)'] - }, { - name: 'fill', - args: [] - }, { - name: 'restore', - args: [] - }]); - }); - - it ('should draw correctly with a border', function() { - var mockContext = window.createMockContext(); - var arc = new Chart.elements.Arc({ - _datasetIndex: 2, - _index: 1, - _chart: { - ctx: mockContext, - } - }); - - // Mock out the view as if the controller put it there - arc._view = { - startAngle: 0, - endAngle: Math.PI / 2, - x: 10, - y: 5, - innerRadius: 1, - outerRadius: 3, - - backgroundColor: 'rgb(0, 0, 255)', - borderColor: 'rgb(255, 0, 0)', - borderWidth: 5 - }; - - arc.draw(); - - expect(mockContext.getCalls()).toEqual([{ - name: 'save', - args: [] - }, { - name: 'beginPath', - args: [] - }, { - name: 'arc', - args: [10, 5, 3, 0, Math.PI / 2] - }, { - name: 'arc', - args: [10, 5, 1, Math.PI / 2, 0, true] - }, { - name: 'closePath', - args: [] - }, { - name: 'setFillStyle', - args: ['rgb(0, 0, 255)'] - }, { - name: 'fill', - args: [] - }, { - name: 'setLineWidth', - args: [5] - }, { - name: 'setLineJoin', - args: ['bevel'] - }, { - name: 'setStrokeStyle', - args: ['rgb(255, 0, 0)'] - }, { - name: 'stroke', - args: [] - }, { - name: 'restore', - args: [] - }]); - }); - - it ('should draw correctly with an inner border', function() { - var mockContext = window.createMockContext(); - var arc = new Chart.elements.Arc({ - _datasetIndex: 2, - _index: 1, - _chart: { - ctx: mockContext, - } - }); - - // Mock out the view as if the controller put it there - arc._view = { - startAngle: 0, - endAngle: Math.PI / 2, - x: 10, - y: 5, - innerRadius: 1, - outerRadius: 3, - - backgroundColor: 'rgb(0, 0, 255)', - borderColor: 'rgb(255, 0, 0)', - borderWidth: 5, - borderAlign: 'inner' - }; - - arc.draw(); - - expect(mockContext.getCalls()).toEqual([{ - name: 'save', - args: [] - }, { - name: 'beginPath', - args: [] - }, { - name: 'arc', - args: [10, 5, 2.67, 0, Math.PI / 2] - }, { - name: 'arc', - args: [10, 5, 1, Math.PI / 2, 0, true] - }, { - name: 'closePath', - args: [] - }, { - name: 'setFillStyle', - args: ['rgb(0, 0, 255)'] - }, { - name: 'fill', - args: [] - }, { - name: 'beginPath', - args: [] - }, { - name: 'arc', - args: [10, 5, 3, -0.11, Math.PI / 2 + 0.11] - }, { - name: 'arc', - args: [10, 5, 1 - 0.33, Math.PI / 2 + 0.33, -0.33, true] - }, { - name: 'closePath', - args: [] - }, { - name: 'clip', - args: [] - }, { - name: 'beginPath', - args: [] - }, { - name: 'arc', - args: [10, 5, 3, 0, Math.PI / 2] - }, { - name: 'arc', - args: [10, 5, 1, Math.PI / 2, 0, true] - }, { - name: 'closePath', - args: [] - }, { - name: 'setLineWidth', - args: [10] - }, { - name: 'setLineJoin', - args: ['round'] - }, { - name: 'setStrokeStyle', - args: ['rgb(255, 0, 0)'] - }, { - name: 'stroke', - args: [] - }, { - name: 'restore', - args: [] - }]); - }); }); From 778105470f5b13a2209b2e2e806471ff94214fee Mon Sep 17 00:00:00 2001 From: Jukka Kurkela Date: Wed, 24 Apr 2019 14:55:35 +0300 Subject: [PATCH 4/6] fill support for circumference > 4PI --- src/elements/element.arc.js | 88 +++++++++--------- .../doughnut-circumference-over-2pi.png | Bin 23064 -> 35638 bytes 2 files changed, 42 insertions(+), 46 deletions(-) diff --git a/src/elements/element.arc.js b/src/elements/element.arc.js index 7acf5cae6a1..1c4334f6307 100644 --- a/src/elements/element.arc.js +++ b/src/elements/element.arc.js @@ -15,33 +15,30 @@ defaults._set('global', { } }); -function pathArc(ctx, x, y, args) { - var innerRadius = args.innerRadius; - var outerRadius = args.outerRadius; - var startAngle = args.startAngle; - var endAngle = args.endAngle; - +function pathArc(ctx, arc) { ctx.beginPath(); - ctx.arc(x, y, outerRadius, startAngle, endAngle); - ctx.arc(x, y, innerRadius, endAngle, startAngle, true); + ctx.arc(arc.x, arc.y, arc.outerRadius, arc.startAngle, arc.endAngle); + ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true); ctx.closePath(); } -function clipArc(ctx, vm, args) { - var startAngle = args.startAngle; - var endAngle = args.endAngle; - var pixelMargin = args.pixelMargin; - var angleMargin = pixelMargin / vm.outerRadius; +function clipArc(ctx, arc) { + var startAngle = arc.startAngle; + var endAngle = arc.endAngle; + var pixelMargin = arc.pixelMargin; + var angleMargin = pixelMargin / arc.outerRadius; + var x = arc.x; + var y = arc.y; // Draw an inner border by cliping the arc and drawing a double-width border // Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders ctx.beginPath(); - ctx.arc(vm.x, vm.y, vm.outerRadius, startAngle - angleMargin, endAngle + angleMargin); - if (vm.innerRadius > pixelMargin) { - angleMargin = pixelMargin / vm.innerRadius; - ctx.arc(vm.x, vm.y, vm.innerRadius - pixelMargin, endAngle + angleMargin, startAngle - angleMargin, true); + ctx.arc(x, y, arc.outerRadius, startAngle - angleMargin, endAngle + angleMargin); + if (arc.innerRadius > pixelMargin) { + angleMargin = pixelMargin / arc.innerRadius; + ctx.arc(x, y, arc.innerRadius - pixelMargin, endAngle + angleMargin, startAngle - angleMargin, true); } else { - ctx.arc(vm.x, vm.y, pixelMargin, endAngle + Math.PI / 2, startAngle - Math.PI / 2); + ctx.arc(x, y, pixelMargin, endAngle + Math.PI / 2, startAngle - Math.PI / 2); } ctx.closePath(); ctx.clip(); @@ -116,45 +113,43 @@ module.exports = Element.extend({ draw: function() { var ctx = this._chart.ctx; var vm = this._view; - var startAngle = vm.startAngle; - var endAngle = vm.endAngle; var pixelMargin = (vm.borderAlign === 'inner') ? 0.33 : 0; - var outerRadius = Math.max(vm.outerRadius - pixelMargin, 0); - var innerRadius = vm.innerRadius; - var x = vm.x; - var y = vm.y; - var tA; + var TAU = Math.PI * 2; + var circumference = vm.endAngle - vm.startAngle; + var arc = { + x: vm.x, + y: vm.y, + innerRadius: vm.innerRadius, + outerRadius: Math.max(vm.outerRadius - pixelMargin, 0), + pixelMargin: pixelMargin, + startAngle: vm.startAngle, + endAngle: vm.endAngle + }; ctx.save(); ctx.fillStyle = vm.backgroundColor; - if (vm.circumference > Math.PI * 2) { - tA = startAngle; - startAngle += (endAngle - startAngle) % (Math.PI * 2); - pathArc(ctx, x, y, { - innerRadius: innerRadius, outerRadius: outerRadius, - startAngle: tA, endAngle: startAngle - }); - ctx.fill(); + if (circumference > TAU) { + arc.endAngle = arc.startAngle + TAU; + pathArc(ctx, arc); + for (; circumference > TAU; circumference -= TAU) { + ctx.fill(); + } + arc.endAngle = arc.startAngle + circumference; } - - pathArc(ctx, x, y, { - innerRadius: innerRadius, outerRadius: outerRadius, - startAngle: startAngle, endAngle: endAngle - }); + pathArc(ctx, arc); ctx.fill(); + if (vm.endAngle > arc.endAngle) { + arc.startAngle = arc.endAngle - TAU; + } + if (vm.borderWidth) { if (vm.borderAlign === 'inner') { - clipArc(ctx, vm, { - startAngle: startAngle, endAngle: endAngle, - pixelMargin: pixelMargin - }); - pathArc(ctx, x, y, { - innerRadius: innerRadius, outerRadius: vm.outerRadius, - startAngle: startAngle, endAngle: endAngle - }); + clipArc(ctx, arc); + + arc.outerRadius = vm.outerRadius; ctx.lineWidth = vm.borderWidth * 2; ctx.lineJoin = 'round'; @@ -162,6 +157,7 @@ module.exports = Element.extend({ ctx.lineWidth = vm.borderWidth; ctx.lineJoin = 'bevel'; } + pathArc(ctx, arc); ctx.strokeStyle = vm.borderColor; ctx.stroke(); diff --git a/test/fixtures/controller.doughnut/doughnut-circumference-over-2pi.png b/test/fixtures/controller.doughnut/doughnut-circumference-over-2pi.png index 6eaf8bccc6940ab077052796393a1a86b6976f20..b918ceb921bc627f98ab5a71cd7c96ff77083d28 100644 GIT binary patch literal 35638 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 literal 23064 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 z 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 Date: Wed, 24 Apr 2019 22:39:13 +0300 Subject: [PATCH 5/6] fix borders --- src/elements/element.arc.js | 107 +++++++++++++++++++++++------------- 1 file changed, 70 insertions(+), 37 deletions(-) diff --git a/src/elements/element.arc.js b/src/elements/element.arc.js index 1c4334f6307..3153c4b932e 100644 --- a/src/elements/element.arc.js +++ b/src/elements/element.arc.js @@ -3,6 +3,7 @@ var defaults = require('../core/core.defaults'); var Element = require('../core/core.element'); var helpers = require('../helpers/index'); +var TAU = Math.PI * 2; defaults._set('global', { elements: { @@ -15,13 +16,6 @@ defaults._set('global', { } }); -function pathArc(ctx, arc) { - ctx.beginPath(); - ctx.arc(arc.x, arc.y, arc.outerRadius, arc.startAngle, arc.endAngle); - ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true); - ctx.closePath(); -} - function clipArc(ctx, arc) { var startAngle = arc.startAngle; var endAngle = arc.endAngle; @@ -44,6 +38,55 @@ function clipArc(ctx, arc) { ctx.clip(); } +function drawFullCircleBorders(ctx, vm, arc, inner) { + var endAngle = arc.endAngle; + var i; + + if (inner) { + arc.endAngle = arc.startAngle + TAU; + clipArc(ctx, arc); + arc.endAngle = endAngle; + } + + ctx.beginPath(); + ctx.arc(arc.x, arc.y, arc.innerRadius, arc.startAngle + TAU, arc.startAngle, true); + for (i = 0; i < arc.fullCircles; ++i) { + ctx.stroke(); + } + + ctx.beginPath(); + ctx.arc(arc.x, arc.y, vm.outerRadius, arc.startAngle, arc.startAngle + TAU); + for (i = 0; i < arc.fullCircles; ++i) { + ctx.stroke(); + } +} + +function drawBorder(ctx, vm, arc) { + var inner = vm.borderAlign === 'inner'; + + if (inner) { + ctx.lineWidth = vm.borderWidth * 2; + ctx.lineJoin = 'round'; + } else { + ctx.lineWidth = vm.borderWidth; + ctx.lineJoin = 'bevel'; + } + + if (vm.endAngle > arc.endAngle) { + drawFullCircleBorders(ctx, vm, arc, inner); + } + + if (inner) { + clipArc(ctx, arc); + } + + ctx.beginPath(); + ctx.arc(arc.x, arc.y, vm.outerRadius, arc.startAngle, arc.endAngle); + ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true); + ctx.closePath(); + ctx.stroke(); +} + module.exports = Element.extend({ inLabelRange: function(mouseX) { var vm = this._view; @@ -66,13 +109,13 @@ module.exports = Element.extend({ var startAngle = vm.startAngle; var endAngle = vm.endAngle; while (endAngle < startAngle) { - endAngle += 2.0 * Math.PI; + endAngle += TAU; } while (angle > endAngle) { - angle -= 2.0 * Math.PI; + angle -= TAU; } while (angle < startAngle) { - angle += 2.0 * Math.PI; + angle += TAU; } // Check if within the range of the open/close angle @@ -114,8 +157,6 @@ module.exports = Element.extend({ var ctx = this._chart.ctx; var vm = this._view; var pixelMargin = (vm.borderAlign === 'inner') ? 0.33 : 0; - var TAU = Math.PI * 2; - var circumference = vm.endAngle - vm.startAngle; var arc = { x: vm.x, y: vm.y, @@ -123,44 +164,36 @@ module.exports = Element.extend({ outerRadius: Math.max(vm.outerRadius - pixelMargin, 0), pixelMargin: pixelMargin, startAngle: vm.startAngle, - endAngle: vm.endAngle + endAngle: vm.endAngle, + fullCircles: Math.floor(vm.circumference / TAU) }; + var i; ctx.save(); ctx.fillStyle = vm.backgroundColor; + ctx.strokeStyle = vm.borderColor; - if (circumference > TAU) { + if (arc.fullCircles) { arc.endAngle = arc.startAngle + TAU; - pathArc(ctx, arc); - for (; circumference > TAU; circumference -= TAU) { + ctx.beginPath(); + ctx.arc(arc.x, arc.y, arc.outerRadius, arc.startAngle, arc.endAngle); + ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true); + ctx.closePath(); + for (i = 0; i < arc.fullCircles; ++i) { ctx.fill(); } - arc.endAngle = arc.startAngle + circumference; + arc.endAngle = arc.startAngle + vm.circumference % TAU; } - pathArc(ctx, arc); - ctx.fill(); - if (vm.endAngle > arc.endAngle) { - arc.startAngle = arc.endAngle - TAU; - } + ctx.beginPath(); + ctx.arc(arc.x, arc.y, arc.outerRadius, arc.startAngle, arc.endAngle); + ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true); + ctx.closePath(); + ctx.fill(); if (vm.borderWidth) { - if (vm.borderAlign === 'inner') { - clipArc(ctx, arc); - - arc.outerRadius = vm.outerRadius; - - ctx.lineWidth = vm.borderWidth * 2; - ctx.lineJoin = 'round'; - } else { - ctx.lineWidth = vm.borderWidth; - ctx.lineJoin = 'bevel'; - } - pathArc(ctx, arc); - - ctx.strokeStyle = vm.borderColor; - ctx.stroke(); + drawBorder(ctx, vm, arc); } ctx.restore(); From 3fd37be7c206fbe5ee7221b6d6ad69137b97bf6c Mon Sep 17 00:00:00 2001 From: Jukka Kurkela Date: Wed, 24 Apr 2019 23:10:42 +0300 Subject: [PATCH 6/6] address even circle border glitch --- src/elements/element.arc.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/elements/element.arc.js b/src/elements/element.arc.js index 3153c4b932e..e3b8875b4dd 100644 --- a/src/elements/element.arc.js +++ b/src/elements/element.arc.js @@ -46,6 +46,10 @@ function drawFullCircleBorders(ctx, vm, arc, inner) { arc.endAngle = arc.startAngle + TAU; clipArc(ctx, arc); arc.endAngle = endAngle; + if (arc.endAngle === arc.startAngle && arc.fullCircles) { + arc.endAngle += TAU; + arc.fullCircles--; + } } ctx.beginPath(); @@ -72,7 +76,7 @@ function drawBorder(ctx, vm, arc) { ctx.lineJoin = 'bevel'; } - if (vm.endAngle > arc.endAngle) { + if (arc.fullCircles) { drawFullCircleBorders(ctx, vm, arc, inner); }