mirror of
https://github.com/chartjs/Chart.js.git
synced 2025-12-08 20:36:08 +00:00
Prevent bezier points from being capped when a data point is off the chart (#5937)
This commit is contained in:
parent
c51ac8a64a
commit
26b7375329
@ -5,6 +5,8 @@ var defaults = require('../core/core.defaults');
|
||||
var elements = require('../elements/index');
|
||||
var helpers = require('../helpers/index');
|
||||
|
||||
var _isPointInArea = helpers.canvas._isPointInArea;
|
||||
|
||||
defaults._set('line', {
|
||||
showLines: true,
|
||||
spanGaps: false,
|
||||
@ -243,13 +245,15 @@ module.exports = DatasetController.extend({
|
||||
|
||||
updateBezierControlPoints: function() {
|
||||
var me = this;
|
||||
var chart = me.chart;
|
||||
var meta = me.getMeta();
|
||||
var area = me.chart.chartArea;
|
||||
var points = (meta.data || []);
|
||||
var lineModel = meta.dataset._model;
|
||||
var area = chart.chartArea;
|
||||
var points = meta.data || [];
|
||||
var i, ilen, point, model, controlPoints;
|
||||
|
||||
// Only consider points that are drawn in case the spanGaps option is used
|
||||
if (meta.dataset._model.spanGaps) {
|
||||
if (lineModel.spanGaps) {
|
||||
points = points.filter(function(pt) {
|
||||
return !pt._model.skip;
|
||||
});
|
||||
@ -259,7 +263,7 @@ module.exports = DatasetController.extend({
|
||||
return Math.max(Math.min(pt, max), min);
|
||||
}
|
||||
|
||||
if (meta.dataset._model.cubicInterpolationMode === 'monotone') {
|
||||
if (lineModel.cubicInterpolationMode === 'monotone') {
|
||||
helpers.splineCurveMonotone(points);
|
||||
} else {
|
||||
for (i = 0, ilen = points.length; i < ilen; ++i) {
|
||||
@ -269,7 +273,7 @@ module.exports = DatasetController.extend({
|
||||
helpers.previousItem(points, i)._model,
|
||||
model,
|
||||
helpers.nextItem(points, i)._model,
|
||||
meta.dataset._model.tension
|
||||
lineModel.tension
|
||||
);
|
||||
model.controlPointPreviousX = controlPoints.previous.x;
|
||||
model.controlPointPreviousY = controlPoints.previous.y;
|
||||
@ -278,13 +282,19 @@ module.exports = DatasetController.extend({
|
||||
}
|
||||
}
|
||||
|
||||
if (me.chart.options.elements.line.capBezierPoints) {
|
||||
if (chart.options.elements.line.capBezierPoints) {
|
||||
for (i = 0, ilen = points.length; i < ilen; ++i) {
|
||||
model = points[i]._model;
|
||||
model.controlPointPreviousX = capControlPoint(model.controlPointPreviousX, area.left, area.right);
|
||||
model.controlPointPreviousY = capControlPoint(model.controlPointPreviousY, area.top, area.bottom);
|
||||
model.controlPointNextX = capControlPoint(model.controlPointNextX, area.left, area.right);
|
||||
model.controlPointNextY = capControlPoint(model.controlPointNextY, area.top, area.bottom);
|
||||
if (_isPointInArea(model, area)) {
|
||||
if (i > 0 && _isPointInArea(points[i - 1]._model, area)) {
|
||||
model.controlPointPreviousX = capControlPoint(model.controlPointPreviousX, area.left, area.right);
|
||||
model.controlPointPreviousY = capControlPoint(model.controlPointPreviousY, area.top, area.bottom);
|
||||
}
|
||||
if (i < points.length - 1 && _isPointInArea(points[i + 1]._model, area)) {
|
||||
model.controlPointNextX = capControlPoint(model.controlPointNextX, area.left, area.right);
|
||||
model.controlPointNextY = capControlPoint(model.controlPointNextY, area.top, area.bottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -65,14 +65,12 @@ module.exports = Element.extend({
|
||||
|
||||
draw: function(chartArea) {
|
||||
var vm = this._view;
|
||||
var model = this._model;
|
||||
var ctx = this._chart.ctx;
|
||||
var pointStyle = vm.pointStyle;
|
||||
var rotation = vm.rotation;
|
||||
var radius = vm.radius;
|
||||
var x = vm.x;
|
||||
var y = vm.y;
|
||||
var epsilon = 0.0000001; // 0.0000001 is margin in pixels for Accumulated error.
|
||||
var globalDefaults = defaults.global;
|
||||
var defaultColor = globalDefaults.defaultColor; // eslint-disable-line no-shadow
|
||||
|
||||
@ -81,7 +79,7 @@ module.exports = Element.extend({
|
||||
}
|
||||
|
||||
// Clipping for Points.
|
||||
if (chartArea === undefined || (model.x > chartArea.left - epsilon && chartArea.right + epsilon > model.x && model.y > chartArea.top - epsilon && chartArea.bottom + epsilon > model.y)) {
|
||||
if (chartArea === undefined || helpers.canvas._isPointInArea(vm, chartArea)) {
|
||||
ctx.strokeStyle = vm.borderColor || defaultColor;
|
||||
ctx.lineWidth = helpers.valueOrDefault(vm.borderWidth, globalDefaults.elements.point.borderWidth);
|
||||
ctx.fillStyle = vm.backgroundColor || defaultColor;
|
||||
|
||||
@ -172,6 +172,20 @@ var exports = {
|
||||
ctx.stroke();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if the point is inside the rectangle
|
||||
* @param {Object} point - The point to test
|
||||
* @param {Object} area - The rectangle
|
||||
* @returns {Boolean}
|
||||
* @private
|
||||
*/
|
||||
_isPointInArea: function(point, area) {
|
||||
var epsilon = 1e-6; // 1e-6 is margin in pixels for accumulated error.
|
||||
|
||||
return point.x > area.left - epsilon && point.x < area.right + epsilon &&
|
||||
point.y > area.top - epsilon && point.y < area.bottom + epsilon;
|
||||
},
|
||||
|
||||
clipArea: function(ctx, area) {
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
|
||||
@ -86,4 +86,18 @@ describe('Chart.helpers.canvas', function() {
|
||||
expect(context.getCalls()).toEqual([{name: 'rect', args: [10, 20, 30, 40]}]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isPointInArea', function() {
|
||||
it('should determine if a point is in the area', function() {
|
||||
var isPointInArea = helpers.canvas._isPointInArea;
|
||||
var area = {left: 0, top: 0, right: 512, bottom: 256};
|
||||
|
||||
expect(isPointInArea({x: 0, y: 0}, area)).toBe(true);
|
||||
expect(isPointInArea({x: -1e-12, y: -1e-12}, area)).toBe(true);
|
||||
expect(isPointInArea({x: 512, y: 256}, area)).toBe(true);
|
||||
expect(isPointInArea({x: 512 + 1e-12, y: 256 + 1e-12}, area)).toBe(true);
|
||||
expect(isPointInArea({x: -1e-3, y: 0}, area)).toBe(false);
|
||||
expect(isPointInArea({x: 0, y: 256 + 1e-3}, area)).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user