From fd0ea21158a6f02e183464cc97e82cbbe1b61653 Mon Sep 17 00:00:00 2001 From: jcopperfield <33193571+jcopperfield@users.noreply.github.com> Date: Wed, 21 Feb 2018 00:44:01 +0100 Subject: [PATCH 1/9] Bugfix: Improve polyfill function of log10 to return whole powers of 10 (#5275) * Bugfix: Improve polyfill function of log10 to return whole powers of 10 as integer values, as it caused endless loop in IE11 in the tick creation loop. * Compare floating-point numbers directly instead of using unnecessary division. rotate works added docs delete line --- docs/charts/bubble.md | 2 ++ docs/charts/line.md | 1 + docs/charts/radar.md | 1 + src/controllers/controller.bubble.js | 5 +++-- src/controllers/controller.line.js | 16 ++++++++++++++ src/controllers/controller.radar.js | 1 + src/elements/element.point.js | 31 ++++++++++++++++++++++------ src/helpers/helpers.canvas.js | 10 ++++++++- 8 files changed, 58 insertions(+), 9 deletions(-) diff --git a/docs/charts/bubble.md b/docs/charts/bubble.md index 4cb2ee6994f..ecc4b79db62 100644 --- a/docs/charts/bubble.md +++ b/docs/charts/bubble.md @@ -51,6 +51,7 @@ The bubble chart allows a number of properties to be specified for each dataset. | [`hitRadius`](#interactions) | `Number` | Yes | Yes | `1` | [`label`](#labeling) | `String` | - | - | `undefined` | [`pointStyle`](#styling) | `String` | Yes | Yes | `circle` +| [`pointRotation`](#styling) | `Number` | Yes | Yes | `0` | [`radius`](#styling) | `Number` | Yes | Yes | `3` ### Labeling @@ -67,6 +68,7 @@ The style of each bubble can be controlled with the following properties: | `borderColor` | bubble border color | `borderWidth` | bubble border width (in pixels) | `pointStyle` | bubble [shape style](../configuration/elements#point-styles) +| `pointRotation` | bubble rotation (in degrees) | `radius` | bubble radius (in pixels) All these values, if `undefined`, fallback to the associated [`elements.point.*`](../configuration/elements.md#point-configuration) options. diff --git a/docs/charts/line.md b/docs/charts/line.md index 90471e462dd..db0245b1e0c 100644 --- a/docs/charts/line.md +++ b/docs/charts/line.md @@ -63,6 +63,7 @@ All point* properties can be specified as an array. If these are set to an array | `pointBorderWidth` | `Number/Number[]` | The width of the point border in pixels. | `pointRadius` | `Number/Number[]` | The radius of the point shape. If set to 0, the point is not rendered. | `pointStyle` | `String/String[]/Image/Image[]` | Style of the point. [more...](../configuration/elements#point-styles) +| `pointRotation` | `Number/Number[]` | The rotation of the point in degrees. | `pointHitRadius` | `Number/Number[]` | The pixel size of the non-displayed point that reacts to mouse events. | `pointHoverBackgroundColor` | `Color/Color[]` | Point background color when hovered. | `pointHoverBorderColor` | `Color/Color[]` | Point border color when hovered. diff --git a/docs/charts/radar.md b/docs/charts/radar.md index b8a41c8384c..947e15a3102 100644 --- a/docs/charts/radar.md +++ b/docs/charts/radar.md @@ -82,6 +82,7 @@ All point* properties can be specified as an array. If these are set to an array | `pointBorderColor` | `Color/Color[]` | The border color for points. | `pointBorderWidth` | `Number/Number[]` | The width of the point border in pixels. | `pointRadius` | `Number/Number[]` | The radius of the point shape. If set to 0, the point is not rendered. +| `pointRotation` | `Number/Number[]` | The rotation of the point in degrees. | `pointStyle` | `String/String[]/Image/Image[]` | Style of the point. [more...](#pointstyle) | `pointHitRadius` | `Number/Number[]` | The pixel size of the non-displayed point that reacts to mouse events. | `pointHoverBackgroundColor` | `Color/Color[]` | Point background color when hovered. diff --git a/src/controllers/controller.bubble.js b/src/controllers/controller.bubble.js index 65c6fae01b8..68247067879 100644 --- a/src/controllers/controller.bubble.js +++ b/src/controllers/controller.bubble.js @@ -87,6 +87,7 @@ module.exports = function(Chart) { borderWidth: options.borderWidth, hitRadius: options.hitRadius, pointStyle: options.pointStyle, + pointRotation: options.pointRotation, radius: reset ? 0 : options.radius, skip: custom.skip || isNaN(x) || isNaN(y), x: x, @@ -154,7 +155,8 @@ module.exports = function(Chart) { 'hoverBorderWidth', 'hoverRadius', 'hitRadius', - 'pointStyle' + 'pointStyle', + 'pointRotation' ]; for (i = 0, ilen = keys.length; i < ilen; ++i) { @@ -173,7 +175,6 @@ module.exports = function(Chart) { dataset.radius, options.radius ], context, index); - return values; } }); diff --git a/src/controllers/controller.line.js b/src/controllers/controller.line.js index 7aacf2d23e2..bd81427e737 100644 --- a/src/controllers/controller.line.js +++ b/src/controllers/controller.line.js @@ -148,6 +148,21 @@ module.exports = function(Chart) { return borderWidth; }, + getPointRotation: function(point, index) { + var pointRotation = this.chart.options.elements.point.pointRotation; + var dataset = this.getDataset(); + var custom = point.custom || {}; + + if (!isNaN(custom.pointRotation)) { + pointRotation = custom.pointRotation; + } else if (!isNaN(dataset.pointRotation) || helpers.isArray(dataset.pointRotation)) { + pointRotation = helpers.valueAtIndexOrDefault(dataset.pointRotation, index, pointRotation); + } else if (!isNaN(dataset.pointRotation)) { + pointRotation = dataset.pointRotation; + } + return pointRotation; + }, + updateElement: function(point, index, reset) { var me = this; var meta = me.getMeta(); @@ -185,6 +200,7 @@ module.exports = function(Chart) { // Appearance radius: custom.radius || helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointOptions.radius), pointStyle: custom.pointStyle || helpers.valueAtIndexOrDefault(dataset.pointStyle, index, pointOptions.pointStyle), + pointRotation: me.getPointRotation(point, index), backgroundColor: me.getPointBackgroundColor(point, index), borderColor: me.getPointBorderColor(point, index), borderWidth: me.getPointBorderWidth(point, index), diff --git a/src/controllers/controller.radar.js b/src/controllers/controller.radar.js index 5de4e4ede0a..9ea0562055a 100644 --- a/src/controllers/controller.radar.js +++ b/src/controllers/controller.radar.js @@ -106,6 +106,7 @@ module.exports = function(Chart) { borderColor: custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor), borderWidth: custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth), pointStyle: custom.pointStyle ? custom.pointStyle : helpers.valueAtIndexOrDefault(dataset.pointStyle, index, pointElementOptions.pointStyle), + pointRotation: custom.pointRotation ? custom.pointRotation : helpers.valueAtIndexOrDefault(dataset.pointRotation, index, pointElementOptions.pointRotation), // Tooltip hitRadius: custom.hitRadius ? custom.hitRadius : helpers.valueAtIndexOrDefault(dataset.pointHitRadius, index, pointElementOptions.hitRadius) diff --git a/src/elements/element.point.js b/src/elements/element.point.js index fa7c42ec641..fe1fb8ff7eb 100644 --- a/src/elements/element.point.js +++ b/src/elements/element.point.js @@ -68,21 +68,40 @@ module.exports = Element.extend({ var model = this._model; var ctx = this._chart.ctx; var pointStyle = vm.pointStyle; + var rotation = vm.pointRotation; var radius = vm.radius; var x = vm.x; var y = vm.y; + var color = helpers.color; var errMargin = 1.01; // 1.01 is margin for Accumulated error. (Especially Edge, IE.) + var ratio = 0; if (vm.skip) { return; } - // Clipping for Points. - if (chartArea === undefined || (model.x >= chartArea.left && chartArea.right * errMargin >= model.x && model.y >= chartArea.top && chartArea.bottom * errMargin >= model.y)) { - ctx.strokeStyle = vm.borderColor || defaultColor; - ctx.lineWidth = helpers.valueOrDefault(vm.borderWidth, defaults.global.elements.point.borderWidth); - ctx.fillStyle = vm.backgroundColor || defaultColor; - helpers.canvas.drawPoint(ctx, pointStyle, radius, x, y); + ctx.strokeStyle = vm.borderColor || defaultColor; + ctx.lineWidth = helpers.valueOrDefault(vm.borderWidth, defaults.global.elements.point.borderWidth); + ctx.fillStyle = vm.backgroundColor || defaultColor; + + // Cliping for Points. + // going out from inner charArea? + if ((chartArea !== undefined) && ((model.x < chartArea.left) || (chartArea.right * errMargin < model.x) || (model.y < chartArea.top) || (chartArea.bottom * errMargin < model.y))) { + // Point fade out + if (model.x < chartArea.left) { + ratio = (x - model.x) / (chartArea.left - model.x); + } else if (chartArea.right * errMargin < model.x) { + ratio = (model.x - x) / (model.x - chartArea.right); + } else if (model.y < chartArea.top) { + ratio = (y - model.y) / (chartArea.top - model.y); + } else if (chartArea.bottom * errMargin < model.y) { + ratio = (model.y - y) / (model.y - chartArea.bottom); + } + ratio = Math.round(ratio * 100) / 100; + ctx.strokeStyle = color(ctx.strokeStyle).alpha(ratio).rgbString(); + ctx.fillStyle = color(ctx.fillStyle).alpha(ratio).rgbString(); } + + helpers.canvas.drawPoint(ctx, pointStyle, radius, x, y, rotation); } }); diff --git a/src/helpers/helpers.canvas.js b/src/helpers/helpers.canvas.js index 13b110268b9..70428ee8ca8 100644 --- a/src/helpers/helpers.canvas.js +++ b/src/helpers/helpers.canvas.js @@ -44,8 +44,9 @@ var exports = module.exports = { } }, - drawPoint: function(ctx, style, radius, x, y) { + drawPoint: function(ctx, style, radius, x, y, rotation) { var type, edgeLength, xOffset, yOffset, height, size; + rotation = rotation || 0; if (style && typeof style === 'object') { type = style.toString(); @@ -59,6 +60,12 @@ var exports = module.exports = { return; } + ctx.save(); + ctx.translate(x, y); + ctx.rotate(rotation * Math.PI / 180); + x = 0; + y = 0; + switch (style) { // Default includes circle default: @@ -150,6 +157,7 @@ var exports = module.exports = { } ctx.stroke(); + ctx.restore(); }, clipArea: function(ctx, area) { From 8cf791018878c732f122af2ca6bb8b686bfbcfe3 Mon Sep 17 00:00:00 2001 From: Joel Hamilton Date: Sun, 4 Mar 2018 15:48:34 -0500 Subject: [PATCH 2/9] added ability to rotate points --- test/specs/element.point.tests.js | 187 ++++++++++++++++++++++++------ 1 file changed, 154 insertions(+), 33 deletions(-) diff --git a/test/specs/element.point.tests.js b/test/specs/element.point.tests.js index f09b912d3c0..55c9fd10f74 100644 --- a/test/specs/element.point.tests.js +++ b/test/specs/element.point.tests.js @@ -108,6 +108,7 @@ describe('Point element tests', function() { point._view = { radius: 2, pointStyle: 'circle', + pointRotation: 25, hitRadius: 3, borderColor: 'rgba(1, 2, 3, 1)', borderWidth: 6, @@ -128,12 +129,21 @@ describe('Point element tests', function() { }, { name: 'setFillStyle', args: ['rgba(0, 255, 0)'] + }, { + name: 'save', + args: [] + }, { + name: 'translate', + args: [10, 15] + }, { + name: 'rotate', + args: [25 * Math.PI / 180] }, { name: 'beginPath', args: [] }, { name: 'arc', - args: [10, 15, 2, 0, 2 * Math.PI] + args: [0, 0, 2, 0, 2 * Math.PI] }, { name: 'closePath', args: [], @@ -143,6 +153,9 @@ describe('Point element tests', function() { }, { name: 'stroke', args: [] + }, { + name: 'restore', + args: [] }]); mockContext.resetCalls(); @@ -158,18 +171,27 @@ describe('Point element tests', function() { }, { name: 'setFillStyle', args: ['rgba(0, 255, 0)'] + }, { + name: 'save', + args: [] + }, { + name: 'translate', + args: [10, 15] + }, { + name: 'rotate', + args: [25 * Math.PI / 180] }, { name: 'beginPath', args: [] }, { name: 'moveTo', - args: [10 - 3 * 2 / Math.sqrt(3) / 2, 15 + 3 * 2 / Math.sqrt(3) * Math.sqrt(3) / 2 / 3] + args: [0 - 3 * 2 / Math.sqrt(3) / 2, 0 + 3 * 2 / Math.sqrt(3) * Math.sqrt(3) / 2 / 3] }, { name: 'lineTo', - args: [10 + 3 * 2 / Math.sqrt(3) / 2, 15 + 3 * 2 / Math.sqrt(3) * Math.sqrt(3) / 2 / 3], + args: [0 + 3 * 2 / Math.sqrt(3) / 2, 0 + 3 * 2 / Math.sqrt(3) * Math.sqrt(3) / 2 / 3], }, { name: 'lineTo', - args: [10, 15 - 2 * 3 * 2 / Math.sqrt(3) * Math.sqrt(3) / 2 / 3], + args: [0, 0 - 2 * 3 * 2 / Math.sqrt(3) * Math.sqrt(3) / 2 / 3], }, { name: 'closePath', args: [], @@ -179,6 +201,9 @@ describe('Point element tests', function() { }, { name: 'stroke', args: [] + }, { + name: 'restore', + args: [] }]); mockContext.resetCalls(); @@ -194,18 +219,30 @@ describe('Point element tests', function() { }, { name: 'setFillStyle', args: ['rgba(0, 255, 0)'] + }, { + name: 'save', + args: [] + }, { + name: 'translate', + args: [10, 15] + }, { + name: 'rotate', + args: [25 * Math.PI / 180] }, { name: 'beginPath', args: [] }, { name: 'fillRect', - args: [10 - 1 / Math.SQRT2 * 2, 15 - 1 / Math.SQRT2 * 2, 2 / Math.SQRT2 * 2, 2 / Math.SQRT2 * 2] + args: [0 - 1 / Math.SQRT2 * 2, 0 - 1 / Math.SQRT2 * 2, 2 / Math.SQRT2 * 2, 2 / Math.SQRT2 * 2] }, { name: 'strokeRect', - args: [10 - 1 / Math.SQRT2 * 2, 15 - 1 / Math.SQRT2 * 2, 2 / Math.SQRT2 * 2, 2 / Math.SQRT2 * 2] + args: [0 - 1 / Math.SQRT2 * 2, 0 - 1 / Math.SQRT2 * 2, 2 / Math.SQRT2 * 2, 2 / Math.SQRT2 * 2] }, { name: 'stroke', args: [] + }, { + name: 'restore', + args: [] }]); var drawRoundedRectangleSpy = jasmine.createSpy('drawRoundedRectangle'); @@ -218,8 +255,8 @@ describe('Point element tests', function() { expect(drawRoundedRectangleSpy).toHaveBeenCalledWith( mockContext, - 10 - offset, - 15 - offset, + 0 - offset, + 0 - offset, Math.SQRT2 * 2, Math.SQRT2 * 2, 2 / 2 @@ -245,21 +282,30 @@ describe('Point element tests', function() { }, { name: 'setFillStyle', args: ['rgba(0, 255, 0)'] + }, { + name: 'save', + args: [] + }, { + name: 'translate', + args: [10, 15] + }, { + name: 'rotate', + args: [25 * Math.PI / 180] }, { name: 'beginPath', args: [] }, { name: 'moveTo', - args: [10 - 1 / Math.SQRT2 * 2, 15] + args: [0 - 1 / Math.SQRT2 * 2, 0] }, { name: 'lineTo', - args: [10, 15 + 1 / Math.SQRT2 * 2] + args: [0, 0 + 1 / Math.SQRT2 * 2] }, { name: 'lineTo', - args: [10 + 1 / Math.SQRT2 * 2, 15], + args: [0 + 1 / Math.SQRT2 * 2, 0], }, { name: 'lineTo', - args: [10, 15 - 1 / Math.SQRT2 * 2], + args: [0, 0 - 1 / Math.SQRT2 * 2], }, { name: 'closePath', args: [] @@ -269,6 +315,9 @@ describe('Point element tests', function() { }, { name: 'stroke', args: [] + }, { + name: 'restore', + args: [] }]); mockContext.resetCalls(); @@ -284,27 +333,39 @@ describe('Point element tests', function() { }, { name: 'setFillStyle', args: ['rgba(0, 255, 0)'] + }, { + name: 'save', + args: [] + }, { + name: 'translate', + args: [10, 15] + }, { + name: 'rotate', + args: [25 * Math.PI / 180] }, { name: 'beginPath', args: [] }, { name: 'moveTo', - args: [10, 17] + args: [0, 2] }, { name: 'lineTo', - args: [10, 13], + args: [0, -2], }, { name: 'moveTo', - args: [8, 15], + args: [-2, 0], }, { name: 'lineTo', - args: [12, 15], + args: [2, 0], }, { name: 'closePath', args: [], }, { name: 'stroke', args: [] + }, { + name: 'restore', + args: [] }]); mockContext.resetCalls(); @@ -320,27 +381,39 @@ describe('Point element tests', function() { }, { name: 'setFillStyle', args: ['rgba(0, 255, 0)'] + }, { + name: 'save', + args: [] + }, { + name: 'translate', + args: [10, 15] + }, { + name: 'rotate', + args: [25 * Math.PI / 180] }, { name: 'beginPath', args: [] }, { name: 'moveTo', - args: [10 - Math.cos(Math.PI / 4) * 2, 15 - Math.sin(Math.PI / 4) * 2] + args: [0 - Math.cos(Math.PI / 4) * 2, 0 - Math.sin(Math.PI / 4) * 2] }, { name: 'lineTo', - args: [10 + Math.cos(Math.PI / 4) * 2, 15 + Math.sin(Math.PI / 4) * 2], + args: [0 + Math.cos(Math.PI / 4) * 2, 0 + Math.sin(Math.PI / 4) * 2], }, { name: 'moveTo', - args: [10 - Math.cos(Math.PI / 4) * 2, 15 + Math.sin(Math.PI / 4) * 2], + args: [0 - Math.cos(Math.PI / 4) * 2, 0 + Math.sin(Math.PI / 4) * 2], }, { name: 'lineTo', - args: [10 + Math.cos(Math.PI / 4) * 2, 15 - Math.sin(Math.PI / 4) * 2], + args: [0 + Math.cos(Math.PI / 4) * 2, 0 - Math.sin(Math.PI / 4) * 2], }, { name: 'closePath', args: [], }, { name: 'stroke', args: [] + }, { + name: 'restore', + args: [] }]); mockContext.resetCalls(); @@ -356,39 +429,51 @@ describe('Point element tests', function() { }, { name: 'setFillStyle', args: ['rgba(0, 255, 0)'] + }, { + name: 'save', + args: [] + }, { + name: 'translate', + args: [10, 15] + }, { + name: 'rotate', + args: [25 * Math.PI / 180] }, { name: 'beginPath', args: [] }, { name: 'moveTo', - args: [10, 17] + args: [0, 2] }, { name: 'lineTo', - args: [10, 13], + args: [0, -2], }, { name: 'moveTo', - args: [8, 15], + args: [-2, 0], }, { name: 'lineTo', - args: [12, 15], + args: [2, 0], }, { name: 'moveTo', - args: [10 - Math.cos(Math.PI / 4) * 2, 15 - Math.sin(Math.PI / 4) * 2] + args: [0 - Math.cos(Math.PI / 4) * 2, 0 - Math.sin(Math.PI / 4) * 2] }, { name: 'lineTo', - args: [10 + Math.cos(Math.PI / 4) * 2, 15 + Math.sin(Math.PI / 4) * 2], + args: [0 + Math.cos(Math.PI / 4) * 2, 0 + Math.sin(Math.PI / 4) * 2], }, { name: 'moveTo', - args: [10 - Math.cos(Math.PI / 4) * 2, 15 + Math.sin(Math.PI / 4) * 2], + args: [0 - Math.cos(Math.PI / 4) * 2, 0 + Math.sin(Math.PI / 4) * 2], }, { name: 'lineTo', - args: [10 + Math.cos(Math.PI / 4) * 2, 15 - Math.sin(Math.PI / 4) * 2], + args: [0 + Math.cos(Math.PI / 4) * 2, 0 - Math.sin(Math.PI / 4) * 2], }, { name: 'closePath', args: [], }, { name: 'stroke', args: [] + }, { + name: 'restore', + args: [] }]); mockContext.resetCalls(); @@ -404,21 +489,33 @@ describe('Point element tests', function() { }, { name: 'setFillStyle', args: ['rgba(0, 255, 0)'] + }, { + name: 'save', + args: [] + }, { + name: 'translate', + args: [10, 15] + }, { + name: 'rotate', + args: [25 * Math.PI / 180] }, { name: 'beginPath', args: [] }, { name: 'moveTo', - args: [8, 15] + args: [-2, 0] }, { name: 'lineTo', - args: [12, 15], + args: [2, 0], }, { name: 'closePath', args: [], }, { name: 'stroke', args: [] + }, { + name: 'restore', + args: [] }]); mockContext.resetCalls(); @@ -434,21 +531,33 @@ describe('Point element tests', function() { }, { name: 'setFillStyle', args: ['rgba(0, 255, 0)'] + }, { + name: 'save', + args: [] + }, { + name: 'translate', + args: [10, 15] + }, { + name: 'rotate', + args: [25 * Math.PI / 180] }, { name: 'beginPath', args: [] }, { name: 'moveTo', - args: [10, 15] + args: [0, 0] }, { name: 'lineTo', - args: [12, 15], + args: [2, 0], }, { name: 'closePath', args: [], }, { name: 'stroke', args: [] + }, { + name: 'restore', + args: [] }]); }); @@ -483,12 +592,21 @@ describe('Point element tests', function() { }, { name: 'setFillStyle', args: ['rgba(0,0,0,0.1)'] + }, { + name: 'save', + args: [] + }, { + name: 'translate', + args: [10, 15] + }, { + name: 'rotate', + args: [0] }, { name: 'beginPath', args: [] }, { name: 'arc', - args: [10, 15, 2, 0, 2 * Math.PI] + args: [0, 0, 2, 0, 2 * Math.PI] }, { name: 'closePath', args: [], @@ -498,6 +616,9 @@ describe('Point element tests', function() { }, { name: 'stroke', args: [] + }, { + name: 'restore', + args: [] }]); }); From d47c278dd37b7a93931bc393ca76858e342a8f3a Mon Sep 17 00:00:00 2001 From: Joel Hamilton Date: Thu, 8 Mar 2018 19:45:15 -0500 Subject: [PATCH 3/9] remove redundant elseif --- src/controllers/controller.line.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/controllers/controller.line.js b/src/controllers/controller.line.js index bd81427e737..80979e589ad 100644 --- a/src/controllers/controller.line.js +++ b/src/controllers/controller.line.js @@ -157,8 +157,6 @@ module.exports = function(Chart) { pointRotation = custom.pointRotation; } else if (!isNaN(dataset.pointRotation) || helpers.isArray(dataset.pointRotation)) { pointRotation = helpers.valueAtIndexOrDefault(dataset.pointRotation, index, pointRotation); - } else if (!isNaN(dataset.pointRotation)) { - pointRotation = dataset.pointRotation; } return pointRotation; }, From b2cb8b17a1498fc6c93e76388f8c0acace1271d8 Mon Sep 17 00:00:00 2001 From: Joel Hamilton Date: Mon, 9 Apr 2018 20:55:27 -0400 Subject: [PATCH 4/9] fix merge conflict --- src/elements/element.point.js | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/src/elements/element.point.js b/src/elements/element.point.js index fe1fb8ff7eb..f0b812cd3d6 100644 --- a/src/elements/element.point.js +++ b/src/elements/element.point.js @@ -72,36 +72,18 @@ module.exports = Element.extend({ var radius = vm.radius; var x = vm.x; var y = vm.y; - var color = helpers.color; var errMargin = 1.01; // 1.01 is margin for Accumulated error. (Especially Edge, IE.) - var ratio = 0; if (vm.skip) { return; } - ctx.strokeStyle = vm.borderColor || defaultColor; - ctx.lineWidth = helpers.valueOrDefault(vm.borderWidth, defaults.global.elements.point.borderWidth); - ctx.fillStyle = vm.backgroundColor || defaultColor; - - // Cliping for Points. - // going out from inner charArea? - if ((chartArea !== undefined) && ((model.x < chartArea.left) || (chartArea.right * errMargin < model.x) || (model.y < chartArea.top) || (chartArea.bottom * errMargin < model.y))) { - // Point fade out - if (model.x < chartArea.left) { - ratio = (x - model.x) / (chartArea.left - model.x); - } else if (chartArea.right * errMargin < model.x) { - ratio = (model.x - x) / (model.x - chartArea.right); - } else if (model.y < chartArea.top) { - ratio = (y - model.y) / (chartArea.top - model.y); - } else if (chartArea.bottom * errMargin < model.y) { - ratio = (model.y - y) / (model.y - chartArea.bottom); - } - ratio = Math.round(ratio * 100) / 100; - ctx.strokeStyle = color(ctx.strokeStyle).alpha(ratio).rgbString(); - ctx.fillStyle = color(ctx.fillStyle).alpha(ratio).rgbString(); + // Clipping for Points. + if (chartArea === undefined || (model.x >= chartArea.left && chartArea.right * errMargin >= model.x && model.y >= chartArea.top && chartArea.bottom * errMargin >= model.y)) { + ctx.strokeStyle = vm.borderColor || defaultColor; + ctx.lineWidth = helpers.valueOrDefault(vm.borderWidth, defaults.global.elements.point.borderWidth); + ctx.fillStyle = vm.backgroundColor || defaultColor; + helpers.canvas.drawPoint(ctx, pointStyle, radius, x, y, rotation); } - - helpers.canvas.drawPoint(ctx, pointStyle, radius, x, y, rotation); } }); From d22d7ce1c0be0e9e1c0592ad1128db52eaa846cc Mon Sep 17 00:00:00 2001 From: Joel Hamilton Date: Fri, 13 Apr 2018 08:12:14 -0400 Subject: [PATCH 5/9] change pointRotation to rotation, add docs --- docs/charts/bubble.md | 2 +- docs/configuration/elements.md | 1 + src/controllers/controller.bubble.js | 4 +- src/controllers/controller.line.js | 8 ++-- src/controllers/controller.radar.js | 2 +- src/elements/element.point.js | 2 +- src/helpers/helpers.canvas.js | 66 ++++++++++++++-------------- test/specs/element.point.tests.js | 2 +- 8 files changed, 43 insertions(+), 44 deletions(-) diff --git a/docs/charts/bubble.md b/docs/charts/bubble.md index ecc4b79db62..d94117ec648 100644 --- a/docs/charts/bubble.md +++ b/docs/charts/bubble.md @@ -68,7 +68,7 @@ The style of each bubble can be controlled with the following properties: | `borderColor` | bubble border color | `borderWidth` | bubble border width (in pixels) | `pointStyle` | bubble [shape style](../configuration/elements#point-styles) -| `pointRotation` | bubble rotation (in degrees) +| `rotation` | bubble rotation (in degrees) | `radius` | bubble radius (in pixels) All these values, if `undefined`, fallback to the associated [`elements.point.*`](../configuration/elements.md#point-configuration) options. diff --git a/docs/configuration/elements.md b/docs/configuration/elements.md index 5375a7e9f1f..148b5f39a54 100644 --- a/docs/configuration/elements.md +++ b/docs/configuration/elements.md @@ -19,6 +19,7 @@ Global point options: `Chart.defaults.global.elements.point` | -----| ---- | --------| ----------- | `radius` | `Number` | `3` | Point radius. | [`pointStyle`](#point-styles) | `String` | `circle` | Point style. +| `rotation` | `Number` | `0` | Point rotation (in degrees). | `backgroundColor` | `Color` | `'rgba(0,0,0,0.1)'` | Point fill color. | `borderWidth` | `Number` | `1` | Point stroke width. | `borderColor` | `Color` | `'rgba(0,0,0,0.1)'` | Point stroke color. diff --git a/src/controllers/controller.bubble.js b/src/controllers/controller.bubble.js index 68247067879..b7b4a7977ae 100644 --- a/src/controllers/controller.bubble.js +++ b/src/controllers/controller.bubble.js @@ -87,7 +87,7 @@ module.exports = function(Chart) { borderWidth: options.borderWidth, hitRadius: options.hitRadius, pointStyle: options.pointStyle, - pointRotation: options.pointRotation, + pointRotation: options.rotation, radius: reset ? 0 : options.radius, skip: custom.skip || isNaN(x) || isNaN(y), x: x, @@ -156,7 +156,7 @@ module.exports = function(Chart) { 'hoverRadius', 'hitRadius', 'pointStyle', - 'pointRotation' + 'rotation' ]; for (i = 0, ilen = keys.length; i < ilen; ++i) { diff --git a/src/controllers/controller.line.js b/src/controllers/controller.line.js index 80979e589ad..4da24aa3fcb 100644 --- a/src/controllers/controller.line.js +++ b/src/controllers/controller.line.js @@ -149,12 +149,12 @@ module.exports = function(Chart) { }, getPointRotation: function(point, index) { - var pointRotation = this.chart.options.elements.point.pointRotation; + var pointRotation = this.chart.options.elements.point.rotation; var dataset = this.getDataset(); var custom = point.custom || {}; - if (!isNaN(custom.pointRotation)) { - pointRotation = custom.pointRotation; + if (!isNaN(custom.rotation)) { + pointRotation = custom.rotation; } else if (!isNaN(dataset.pointRotation) || helpers.isArray(dataset.pointRotation)) { pointRotation = helpers.valueAtIndexOrDefault(dataset.pointRotation, index, pointRotation); } @@ -198,7 +198,7 @@ module.exports = function(Chart) { // Appearance radius: custom.radius || helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointOptions.radius), pointStyle: custom.pointStyle || helpers.valueAtIndexOrDefault(dataset.pointStyle, index, pointOptions.pointStyle), - pointRotation: me.getPointRotation(point, index), + rotation: me.getPointRotation(point, index), backgroundColor: me.getPointBackgroundColor(point, index), borderColor: me.getPointBorderColor(point, index), borderWidth: me.getPointBorderWidth(point, index), diff --git a/src/controllers/controller.radar.js b/src/controllers/controller.radar.js index 9ea0562055a..7f119006771 100644 --- a/src/controllers/controller.radar.js +++ b/src/controllers/controller.radar.js @@ -106,7 +106,7 @@ module.exports = function(Chart) { borderColor: custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor), borderWidth: custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth), pointStyle: custom.pointStyle ? custom.pointStyle : helpers.valueAtIndexOrDefault(dataset.pointStyle, index, pointElementOptions.pointStyle), - pointRotation: custom.pointRotation ? custom.pointRotation : helpers.valueAtIndexOrDefault(dataset.pointRotation, index, pointElementOptions.pointRotation), + rotation: custom.rotation ? custom.rotation : helpers.valueAtIndexOrDefault(dataset.pointRotation, index, pointElementOptions.rotation), // Tooltip hitRadius: custom.hitRadius ? custom.hitRadius : helpers.valueAtIndexOrDefault(dataset.pointHitRadius, index, pointElementOptions.hitRadius) diff --git a/src/elements/element.point.js b/src/elements/element.point.js index f0b812cd3d6..2bcdc88f0f8 100644 --- a/src/elements/element.point.js +++ b/src/elements/element.point.js @@ -68,7 +68,7 @@ module.exports = Element.extend({ var model = this._model; var ctx = this._chart.ctx; var pointStyle = vm.pointStyle; - var rotation = vm.pointRotation; + var rotation = vm.rotation; var radius = vm.radius; var x = vm.x; var y = vm.y; diff --git a/src/helpers/helpers.canvas.js b/src/helpers/helpers.canvas.js index 70428ee8ca8..cc94d01c83a 100644 --- a/src/helpers/helpers.canvas.js +++ b/src/helpers/helpers.canvas.js @@ -63,14 +63,12 @@ var exports = module.exports = { ctx.save(); ctx.translate(x, y); ctx.rotate(rotation * Math.PI / 180); - x = 0; - y = 0; switch (style) { // Default includes circle default: ctx.beginPath(); - ctx.arc(x, y, radius, 0, Math.PI * 2); + ctx.arc(0, 0, radius, 0, Math.PI * 2); ctx.closePath(); ctx.fill(); break; @@ -78,22 +76,22 @@ var exports = module.exports = { ctx.beginPath(); edgeLength = 3 * radius / Math.sqrt(3); height = edgeLength * Math.sqrt(3) / 2; - ctx.moveTo(x - edgeLength / 2, y + height / 3); - ctx.lineTo(x + edgeLength / 2, y + height / 3); - ctx.lineTo(x, y - 2 * height / 3); + ctx.moveTo(edgeLength / 2, height / 3); + ctx.lineTo(edgeLength / 2, height / 3); + ctx.lineTo(0, 0 - 2 * height / 3); ctx.closePath(); ctx.fill(); break; case 'rect': size = 1 / Math.SQRT2 * radius; ctx.beginPath(); - ctx.fillRect(x - size, y - size, 2 * size, 2 * size); - ctx.strokeRect(x - size, y - size, 2 * size, 2 * size); + ctx.fillRect(size, size, 2 * size, 2 * size); + ctx.strokeRect(size, size, 2 * size, 2 * size); break; case 'rectRounded': var offset = radius / Math.SQRT2; - var leftX = x - offset; - var topY = y - offset; + var leftX = offset; + var topY = offset; var sideSize = Math.SQRT2 * radius; ctx.beginPath(); this.roundedRect(ctx, leftX, topY, sideSize, sideSize, radius / 2); @@ -103,55 +101,55 @@ var exports = module.exports = { case 'rectRot': size = 1 / Math.SQRT2 * radius; ctx.beginPath(); - ctx.moveTo(x - size, y); - ctx.lineTo(x, y + size); - ctx.lineTo(x + size, y); - ctx.lineTo(x, y - size); + ctx.moveTo(size, 0); + ctx.lineTo(0, size); + ctx.lineTo(size, 0); + ctx.lineTo(0, size); ctx.closePath(); ctx.fill(); break; case 'cross': ctx.beginPath(); - ctx.moveTo(x, y + radius); - ctx.lineTo(x, y - radius); - ctx.moveTo(x - radius, y); - ctx.lineTo(x + radius, y); + ctx.moveTo(0, radius); + ctx.lineTo(0, radius); + ctx.moveTo(radius, 0); + ctx.lineTo(radius, 0); ctx.closePath(); break; case 'crossRot': ctx.beginPath(); xOffset = Math.cos(Math.PI / 4) * radius; yOffset = Math.sin(Math.PI / 4) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x - xOffset, y + yOffset); - ctx.lineTo(x + xOffset, y - yOffset); + ctx.moveTo(xOffset, yOffset); + ctx.lineTo(xOffset, yOffset); + ctx.moveTo(xOffset, yOffset); + ctx.lineTo(xOffset, yOffset); ctx.closePath(); break; case 'star': ctx.beginPath(); - ctx.moveTo(x, y + radius); - ctx.lineTo(x, y - radius); - ctx.moveTo(x - radius, y); - ctx.lineTo(x + radius, y); + ctx.moveTo(0, radius); + ctx.lineTo(0, radius); + ctx.moveTo(radius, 0); + ctx.lineTo(radius, 0); xOffset = Math.cos(Math.PI / 4) * radius; yOffset = Math.sin(Math.PI / 4) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x - xOffset, y + yOffset); - ctx.lineTo(x + xOffset, y - yOffset); + ctx.moveTo(xOffset, yOffset); + ctx.lineTo(xOffset, yOffset); + ctx.moveTo(xOffset, yOffset); + ctx.lineTo(xOffset, yOffset); ctx.closePath(); break; case 'line': ctx.beginPath(); - ctx.moveTo(x - radius, y); - ctx.lineTo(x + radius, y); + ctx.moveTo(radius, 0); + ctx.lineTo(radius, 0); ctx.closePath(); break; case 'dash': ctx.beginPath(); - ctx.moveTo(x, y); - ctx.lineTo(x + radius, y); + ctx.moveTo(0, 0); + ctx.lineTo(radius, 0); ctx.closePath(); break; } diff --git a/test/specs/element.point.tests.js b/test/specs/element.point.tests.js index 55c9fd10f74..57d07550b68 100644 --- a/test/specs/element.point.tests.js +++ b/test/specs/element.point.tests.js @@ -108,7 +108,7 @@ describe('Point element tests', function() { point._view = { radius: 2, pointStyle: 'circle', - pointRotation: 25, + rotation: 25, hitRadius: 3, borderColor: 'rgba(1, 2, 3, 1)', borderWidth: 6, From d182d34b99516572828001cb328549c89034652e Mon Sep 17 00:00:00 2001 From: Joel Hamilton Date: Fri, 13 Apr 2018 08:27:43 -0400 Subject: [PATCH 6/9] fix draw point --- src/helpers/helpers.canvas.js | 38 +++++++++++++++++------------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/helpers/helpers.canvas.js b/src/helpers/helpers.canvas.js index cc94d01c83a..9c7dbeb42e3 100644 --- a/src/helpers/helpers.canvas.js +++ b/src/helpers/helpers.canvas.js @@ -76,22 +76,22 @@ var exports = module.exports = { ctx.beginPath(); edgeLength = 3 * radius / Math.sqrt(3); height = edgeLength * Math.sqrt(3) / 2; - ctx.moveTo(edgeLength / 2, height / 3); + ctx.moveTo(-edgeLength / 2, height / 3); ctx.lineTo(edgeLength / 2, height / 3); - ctx.lineTo(0, 0 - 2 * height / 3); + ctx.lineTo(0, -2 * height / 3); ctx.closePath(); ctx.fill(); break; case 'rect': size = 1 / Math.SQRT2 * radius; ctx.beginPath(); - ctx.fillRect(size, size, 2 * size, 2 * size); - ctx.strokeRect(size, size, 2 * size, 2 * size); + ctx.fillRect(-size, -size, 2 * size, 2 * size); + ctx.strokeRect(-size, -size, 2 * size, 2 * size); break; case 'rectRounded': var offset = radius / Math.SQRT2; - var leftX = offset; - var topY = offset; + var leftX = -offset; + var topY = -offset; var sideSize = Math.SQRT2 * radius; ctx.beginPath(); this.roundedRect(ctx, leftX, topY, sideSize, sideSize, radius / 2); @@ -101,18 +101,18 @@ var exports = module.exports = { case 'rectRot': size = 1 / Math.SQRT2 * radius; ctx.beginPath(); - ctx.moveTo(size, 0); + ctx.moveTo(-size, 0); ctx.lineTo(0, size); ctx.lineTo(size, 0); - ctx.lineTo(0, size); + ctx.lineTo(0, -size); ctx.closePath(); ctx.fill(); break; case 'cross': ctx.beginPath(); ctx.moveTo(0, radius); - ctx.lineTo(0, radius); - ctx.moveTo(radius, 0); + ctx.lineTo(0, -radius); + ctx.moveTo(-radius, 0); ctx.lineTo(radius, 0); ctx.closePath(); break; @@ -120,29 +120,29 @@ var exports = module.exports = { ctx.beginPath(); xOffset = Math.cos(Math.PI / 4) * radius; yOffset = Math.sin(Math.PI / 4) * radius; - ctx.moveTo(xOffset, yOffset); - ctx.lineTo(xOffset, yOffset); - ctx.moveTo(xOffset, yOffset); + ctx.moveTo(-xOffset, -yOffset); ctx.lineTo(xOffset, yOffset); + ctx.moveTo(-xOffset, yOffset); + ctx.lineTo(xOffset, -yOffset); ctx.closePath(); break; case 'star': ctx.beginPath(); ctx.moveTo(0, radius); - ctx.lineTo(0, radius); - ctx.moveTo(radius, 0); + ctx.lineTo(0, -radius); + ctx.moveTo(-radius, 0); ctx.lineTo(radius, 0); xOffset = Math.cos(Math.PI / 4) * radius; yOffset = Math.sin(Math.PI / 4) * radius; - ctx.moveTo(xOffset, yOffset); - ctx.lineTo(xOffset, yOffset); - ctx.moveTo(xOffset, yOffset); + ctx.moveTo(-xOffset, -yOffset); ctx.lineTo(xOffset, yOffset); + ctx.moveTo(-xOffset, yOffset); + ctx.lineTo(xOffset, -yOffset); ctx.closePath(); break; case 'line': ctx.beginPath(); - ctx.moveTo(radius, 0); + ctx.moveTo(-radius, 0); ctx.lineTo(radius, 0); ctx.closePath(); break; From da235999255be63b99c74de624fedbfba1eeb12c Mon Sep 17 00:00:00 2001 From: Joel Hamilton Date: Thu, 31 May 2018 14:32:41 -0400 Subject: [PATCH 7/9] rotation -> pointRotation --- docs/charts/bubble.md | 2 +- src/controllers/controller.bubble.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/charts/bubble.md b/docs/charts/bubble.md index d94117ec648..ecc4b79db62 100644 --- a/docs/charts/bubble.md +++ b/docs/charts/bubble.md @@ -68,7 +68,7 @@ The style of each bubble can be controlled with the following properties: | `borderColor` | bubble border color | `borderWidth` | bubble border width (in pixels) | `pointStyle` | bubble [shape style](../configuration/elements#point-styles) -| `rotation` | bubble rotation (in degrees) +| `pointRotation` | bubble rotation (in degrees) | `radius` | bubble radius (in pixels) All these values, if `undefined`, fallback to the associated [`elements.point.*`](../configuration/elements.md#point-configuration) options. diff --git a/src/controllers/controller.bubble.js b/src/controllers/controller.bubble.js index b7b4a7977ae..137d01d5dc5 100644 --- a/src/controllers/controller.bubble.js +++ b/src/controllers/controller.bubble.js @@ -156,7 +156,7 @@ module.exports = function(Chart) { 'hoverRadius', 'hitRadius', 'pointStyle', - 'rotation' + 'pointRotation' ]; for (i = 0, ilen = keys.length; i < ilen; ++i) { From 6b9dfaf00750e5f2b1e9243d8d35251fc50bbc69 Mon Sep 17 00:00:00 2001 From: Joel Hamilton Date: Wed, 20 Jun 2018 18:26:25 -0400 Subject: [PATCH 8/9] rename bubble options for point rotation --- docs/charts/bubble.md | 2 +- src/controllers/controller.bubble.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/charts/bubble.md b/docs/charts/bubble.md index ecc4b79db62..fc1e0386c4a 100644 --- a/docs/charts/bubble.md +++ b/docs/charts/bubble.md @@ -51,7 +51,7 @@ The bubble chart allows a number of properties to be specified for each dataset. | [`hitRadius`](#interactions) | `Number` | Yes | Yes | `1` | [`label`](#labeling) | `String` | - | - | `undefined` | [`pointStyle`](#styling) | `String` | Yes | Yes | `circle` -| [`pointRotation`](#styling) | `Number` | Yes | Yes | `0` +| [`rotation`](#styling) | `Number` | Yes | Yes | `0` | [`radius`](#styling) | `Number` | Yes | Yes | `3` ### Labeling diff --git a/src/controllers/controller.bubble.js b/src/controllers/controller.bubble.js index 137d01d5dc5..5df7bb08af8 100644 --- a/src/controllers/controller.bubble.js +++ b/src/controllers/controller.bubble.js @@ -87,7 +87,7 @@ module.exports = function(Chart) { borderWidth: options.borderWidth, hitRadius: options.hitRadius, pointStyle: options.pointStyle, - pointRotation: options.rotation, + rotation: options.rotation, radius: reset ? 0 : options.radius, skip: custom.skip || isNaN(x) || isNaN(y), x: x, From 71ae83a0a92b23b06ffad6785d3af3a57b772e76 Mon Sep 17 00:00:00 2001 From: Joel Hamilton Date: Sat, 7 Jul 2018 08:58:27 -0400 Subject: [PATCH 9/9] change pointRotation -> rotation --- docs/charts/bubble.md | 2 +- src/controllers/controller.bubble.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/charts/bubble.md b/docs/charts/bubble.md index fc1e0386c4a..e9f8a7216b1 100644 --- a/docs/charts/bubble.md +++ b/docs/charts/bubble.md @@ -68,7 +68,7 @@ The style of each bubble can be controlled with the following properties: | `borderColor` | bubble border color | `borderWidth` | bubble border width (in pixels) | `pointStyle` | bubble [shape style](../configuration/elements#point-styles) -| `pointRotation` | bubble rotation (in degrees) +| `rotation` | bubble rotation (in degrees) | `radius` | bubble radius (in pixels) All these values, if `undefined`, fallback to the associated [`elements.point.*`](../configuration/elements.md#point-configuration) options. diff --git a/src/controllers/controller.bubble.js b/src/controllers/controller.bubble.js index 5df7bb08af8..fe62af913d3 100644 --- a/src/controllers/controller.bubble.js +++ b/src/controllers/controller.bubble.js @@ -156,7 +156,7 @@ module.exports = function(Chart) { 'hoverRadius', 'hitRadius', 'pointStyle', - 'pointRotation' + 'rotation' ]; for (i = 0, ilen = keys.length; i < ilen; ++i) {