import Element from '../core/core.element';
-import {_angleBetween, getAngleFromPoint, TAU, HALF_PI} from '../helpers/index';
-import {PI, _limitValue} from '../helpers/helpers.math';
+import {_angleBetween, getAngleFromPoint, TAU, HALF_PI, valueOrDefault} from '../helpers/index';
+import {PI, _isBetween, _limitValue} from '../helpers/helpers.math';
import {_readValueToProps} from '../helpers/helpers.options';
function clipArc(ctx, element, endAngle) {
'circumference'
], useFinalPosition);
const rAdjust = this.options.spacing / 2;
- const betweenAngles = circumference >= TAU || _angleBetween(angle, startAngle, endAngle);
- const withinRadius = (distance >= innerRadius + rAdjust && distance <= outerRadius + rAdjust);
+ const _circumference = valueOrDefault(circumference, endAngle - startAngle);
+ const betweenAngles = _circumference >= TAU || _angleBetween(angle, startAngle, endAngle);
+ const withinRadius = _isBetween(distance, innerRadius + rAdjust, outerRadius + rAdjust);
return (betweenAngles && withinRadius);
}
import Element from '../core/core.element';
-import {isObject, _limitValue} from '../helpers';
+import {isObject, _isBetween, _limitValue} from '../helpers';
import {addRoundedRectPath} from '../helpers/helpers.canvas';
import {toTRBL, toTRBLCorners} from '../helpers/helpers.options';
const bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition);
return bounds
- && (skipX || x >= bounds.left && x <= bounds.right)
- && (skipY || y >= bounds.top && y <= bounds.bottom);
+ && (skipX || _isBetween(x, bounds.left, bounds.right))
+ && (skipY || _isBetween(y, bounds.top, bounds.bottom));
}
function hasRadius(radius) {
return Math.max(min, Math.min(max, value));
}
+/**
+ * @param {number} value
+ * @private
+ */
export function _int16Range(value) {
return _limitValue(value, -32768, 32767);
}
+
+/**
+ * @param {number} value
+ * @param {number} start
+ * @param {number} end
+ * @param {number} [epsilon]
+ * @private
+ */
+export function _isBetween(value, start, end, epsilon = 1e-6) {
+ return value >= Math.min(start, end) - epsilon && value <= Math.max(start, end) + epsilon;
+}
-import {_angleBetween, _angleDiff, _normalizeAngle} from './helpers.math';
+import {_angleBetween, _angleDiff, _isBetween, _normalizeAngle} from './helpers.math';
import {createContext} from './helpers.options';
/**
};
}
return {
- between: (n, s, e) => n >= Math.min(s, e) && n <= Math.max(e, s),
+ between: _isBetween,
compare: (a, b) => a - b,
normalize: x => x
};
import {_boundSegment, _boundSegments} from '../helpers/helpers.segment';
import {clipArea, unclipArea} from '../helpers/helpers.canvas';
import {isArray, isFinite, isObject, valueOrDefault} from '../helpers/helpers.core';
-import {TAU, _normalizeAngle} from '../helpers/helpers.math';
+import {TAU, _isBetween, _normalizeAngle} from '../helpers/helpers.math';
/**
* @typedef { import('../core/core.controller').default } Chart
const segment = segments[i];
const firstValue = linePoints[segment.start][property];
const lastValue = linePoints[segment.end][property];
- if (pointValue >= firstValue && pointValue <= lastValue) {
+ if (_isBetween(pointValue, firstValue, lastValue)) {
first = pointValue === firstValue;
last = pointValue === lastValue;
break;
import {
callback as call, valueOrDefault, toFont,
toPadding, getRtlAdapter, overrideTextDirection, restoreTextDirection,
- clipArea, unclipArea
+ clipArea, unclipArea, _isBetween
} from '../helpers/index';
import {_toLeftRightCenter, _alignStartEnd, _textX} from '../helpers/helpers.extras';
import {toTRBLCorners} from '../helpers/helpers.options';
_getLegendItemAt(x, y) {
let i, hitBox, lh;
- if (x >= this.left && x <= this.right && y >= this.top && y <= this.bottom) {
+ if (_isBetween(x, this.left, this.right)
+ && _isBetween(y, this.top, this.bottom)) {
// See if we are touching one of the dataset boxes
lh = this.legendHitBoxes;
for (i = 0; i < lh.length; ++i) {
hitBox = lh[i];
- if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) {
+ if (_isBetween(x, hitBox.left, hitBox.left + hitBox.width)
+ && _isBetween(y, hitBox.top, hitBox.top + hitBox.height)) {
// Touching an element
return this.legendItems[i];
}
expect(arc.inRange(-1.0 * Math.sqrt(7), Math.sqrt(7))).toBe(false);
});
+ it ('should determine if in range when full circle', function() {
+ // Mock out the arc as if the controller put it there
+ var arc = new Chart.elements.ArcElement({
+ startAngle: 0,
+ endAngle: Math.PI * 2,
+ x: 0,
+ y: 0,
+ innerRadius: 5,
+ outerRadius: 10,
+ options: {
+ spacing: 0,
+ offset: 0,
+ }
+ });
+
+ for (const radius of [5, 7.5, 10]) {
+ for (let angle = 0; angle <= 360; angle += 22.5) {
+ const rad = angle / 180 * Math.PI;
+ const x = Math.sin(rad) * radius;
+ const y = Math.cos(rad) * radius;
+ expect(arc.inRange(x, y)).withContext(`radius: ${radius}, angle: ${angle}`).toBeTrue();
+ }
+ }
+ for (const radius of [4, 11]) {
+ for (let angle = 0; angle <= 360; angle += 22.5) {
+ const rad = angle / 180 * Math.PI;
+ const x = Math.sin(rad) * radius;
+ const y = Math.cos(rad) * radius;
+ expect(arc.inRange(x, y)).withContext(`radius: ${radius}, angle: ${angle}`).toBeFalse();
+ }
+ }
+ });
+
it ('should include spacing for in range check', function() {
// Mock out the arc as if the controller put it there
var arc = new Chart.elements.ArcElement({