mirror of
https://github.com/chartjs/Chart.js.git
synced 2025-12-08 20:36:08 +00:00
Fix inRange for full circle arc (#9871)
* Update misleading sample comment * Fix inRange for full circle arc
This commit is contained in:
parent
0dc733a96c
commit
0c5db4973e
@ -1,6 +1,6 @@
|
||||
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) {
|
||||
@ -282,8 +282,9 @@ export default class ArcElement extends Element {
|
||||
'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);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
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';
|
||||
|
||||
@ -105,8 +105,8 @@ function inRange(bar, x, y, useFinalPosition) {
|
||||
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) {
|
||||
|
||||
@ -173,6 +173,21 @@ export function _limitValue(value, min, max) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {_angleBetween, _angleDiff, _normalizeAngle} from './helpers.math';
|
||||
import {_angleBetween, _angleDiff, _isBetween, _normalizeAngle} from './helpers.math';
|
||||
import {createContext} from './helpers.options';
|
||||
|
||||
/**
|
||||
@ -16,7 +16,7 @@ function propertyFn(property) {
|
||||
};
|
||||
}
|
||||
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
|
||||
};
|
||||
|
||||
@ -8,7 +8,7 @@ import LineElement from '../elements/element.line';
|
||||
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
|
||||
@ -293,7 +293,7 @@ function findPoint(line, sourcePoint, property) {
|
||||
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;
|
||||
|
||||
@ -5,7 +5,7 @@ import {addRoundedRectPath, drawPoint, renderText} from '../helpers/helpers.canv
|
||||
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';
|
||||
@ -493,13 +493,15 @@ export class Legend extends Element {
|
||||
_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];
|
||||
}
|
||||
|
||||
@ -23,6 +23,39 @@ describe('Arc element tests', function() {
|
||||
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({
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user