Convert the curve helpers to TS (#10733)

* Convert the curve helpers to TS
* Remove old type
This commit is contained in:
Evert Timberg 2022-10-07 08:28:24 -04:00 committed by GitHub
parent 06bbadb00f
commit 41612d1320
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 50 additions and 65 deletions

View File

@ -1,11 +1,35 @@
import {almostEquals, distanceBetweenPoints, sign} from './helpers.math';
import {_isPointInArea} from './helpers.canvas';
import {ChartArea} from '../../types';
export interface SplinePoint {
x: number;
y: number;
skip?: boolean;
// Both Bezier and monotone interpolations have these fields
// but they are added in different spots
cp1x?: number;
cp1y?: number;
cp2x?: number;
cp2y?: number;
}
const EPSILON = Number.EPSILON || 1e-14;
const getPoint = (points, i) => i < points.length && !points[i].skip && points[i];
const getValueAxis = (indexAxis) => indexAxis === 'x' ? 'y' : 'x';
export function splineCurve(firstPoint, middlePoint, afterPoint, t) {
type OptionalSplinePoint = SplinePoint | false
const getPoint = (points: SplinePoint[], i: number): OptionalSplinePoint => i < points.length && !points[i].skip && points[i];
const getValueAxis = (indexAxis: 'x' | 'y') => indexAxis === 'x' ? 'y' : 'x';
export function splineCurve(
firstPoint: SplinePoint,
middlePoint: SplinePoint,
afterPoint: SplinePoint,
t: number
): {
previous: SplinePoint
next: SplinePoint
} {
// Props to Rob Spencer at scaled innovation for his post on splining between points
// http://scaledinnovation.com/analytics/splines/aboutSplines.html
@ -42,10 +66,10 @@ export function splineCurve(firstPoint, middlePoint, afterPoint, t) {
/**
* Adjust tangents to ensure monotonic properties
*/
function monotoneAdjust(points, deltaK, mK) {
function monotoneAdjust(points: SplinePoint[], deltaK: number[], mK: number[]) {
const pointsLen = points.length;
let alphaK, betaK, tauK, squaredMagnitude, pointCurrent;
let alphaK: number, betaK: number, tauK: number, squaredMagnitude: number, pointCurrent: OptionalSplinePoint;
let pointAfter = getPoint(points, 0);
for (let i = 0; i < pointsLen - 1; ++i) {
pointCurrent = pointAfter;
@ -72,10 +96,10 @@ function monotoneAdjust(points, deltaK, mK) {
}
}
function monotoneCompute(points, mK, indexAxis = 'x') {
function monotoneCompute(points: SplinePoint[], mK: number[], indexAxis: 'x' | 'y' = 'x') {
const valueAxis = getValueAxis(indexAxis);
const pointsLen = points.length;
let delta, pointBefore, pointCurrent;
let delta: number, pointBefore: OptionalSplinePoint, pointCurrent: OptionalSplinePoint;
let pointAfter = getPoint(points, 0);
for (let i = 0; i < pointsLen; ++i) {
@ -106,26 +130,15 @@ function monotoneCompute(points, mK, indexAxis = 'x') {
* but preserves monotonicity of the provided data and ensures no local extremums are added
* between the dataset discrete points due to the interpolation.
* See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
*
* @param {{
* x: number,
* y: number,
* skip?: boolean,
* cp1x?: number,
* cp1y?: number,
* cp2x?: number,
* cp2y?: number,
* }[]} points
* @param {string} indexAxis
*/
export function splineCurveMonotone(points, indexAxis = 'x') {
export function splineCurveMonotone(points: SplinePoint[], indexAxis: 'x' | 'y' = 'x') {
const valueAxis = getValueAxis(indexAxis);
const pointsLen = points.length;
const deltaK = Array(pointsLen).fill(0);
const mK = Array(pointsLen);
const deltaK: number[] = Array(pointsLen).fill(0);
const mK: number[] = Array(pointsLen);
// Calculate slopes (deltaK) and initialize tangents (mK)
let i, pointBefore, pointCurrent;
let i, pointBefore: OptionalSplinePoint, pointCurrent: OptionalSplinePoint;
let pointAfter = getPoint(points, 0);
for (i = 0; i < pointsLen; ++i) {
@ -144,8 +157,8 @@ export function splineCurveMonotone(points, indexAxis = 'x') {
}
mK[i] = !pointBefore ? deltaK[i]
: !pointAfter ? deltaK[i - 1]
: (sign(deltaK[i - 1]) !== sign(deltaK[i])) ? 0
: (deltaK[i - 1] + deltaK[i]) / 2;
: (sign(deltaK[i - 1]) !== sign(deltaK[i])) ? 0
: (deltaK[i - 1] + deltaK[i]) / 2;
}
monotoneAdjust(points, deltaK, mK);
@ -153,11 +166,11 @@ export function splineCurveMonotone(points, indexAxis = 'x') {
monotoneCompute(points, mK, indexAxis);
}
function capControlPoint(pt, min, max) {
function capControlPoint(pt: number, min: number, max: number) {
return Math.max(Math.min(pt, max), min);
}
function capBezierPoints(points, area) {
function capBezierPoints(points: SplinePoint[], area: ChartArea) {
let i, ilen, point, inArea, inAreaPrev;
let inAreaNext = _isPointInArea(points[0], area);
for (i = 0, ilen = points.length; i < ilen; ++i) {
@ -182,8 +195,14 @@ function capBezierPoints(points, area) {
/**
* @private
*/
export function _updateBezierControlPoints(points, options, area, loop, indexAxis) {
let i, ilen, point, controlPoints;
export function _updateBezierControlPoints(
points: SplinePoint[],
options,
area: ChartArea,
loop: boolean,
indexAxis: 'x' | 'y'
) {
let i: number, ilen: number, point: SplinePoint, controlPoints: ReturnType<typeof splineCurve>;
// Only consider points that are drawn in case the spanGaps option is used
if (options.spanGaps) {

View File

@ -1,5 +1,5 @@
import type {Point} from '../../types/geometric';
import type {MonotoneSplinePoint} from '../../types/helpers';
import type {SplinePoint} from './helpers.curve';
/**
* @private
@ -30,7 +30,7 @@ export function _steppedInterpolation(
/**
* @private
*/
export function _bezierInterpolation(p1: MonotoneSplinePoint, p2: MonotoneSplinePoint, t: number, mode?) { // eslint-disable-line @typescript-eslint/no-unused-vars
export function _bezierInterpolation(p1: SplinePoint, p2: SplinePoint, t: number, mode?) { // eslint-disable-line @typescript-eslint/no-unused-vars
const cp1 = {x: p1.cp2x, y: p1.cp2y};
const cp2 = {x: p2.cp1x, y: p2.cp1y};
const a = _pointInLine(p1, cp1, t);

View File

@ -7,6 +7,7 @@
export * from './helpers.color';
export * from './helpers.collection';
export * from './helpers.core';
export * from './helpers.curve';
export * from './helpers.easing';
export * from './helpers.extras';
export * from './helpers.interpolation';

View File

@ -1,34 +0,0 @@
export interface SplinePoint {
x: number;
y: number;
}
/**
* Props to Rob Spencer at scaled innovation for his post on splining between points
* http://scaledinnovation.com/analytics/splines/aboutSplines.html
*/
export function splineCurve(
firstPoint: SplinePoint & { skip?: boolean },
middlePoint: SplinePoint,
afterPoint: SplinePoint,
t: number
): {
previous: SplinePoint;
next: SplinePoint;
};
export interface MonotoneSplinePoint extends SplinePoint {
skip: boolean;
cp1x?: number;
cp1y?: number;
cp2x?: number;
cp2y?: number;
}
/**
* This function calculates Bézier control points in a similar way than |splineCurve|,
* but preserves monotonicity of the provided data and ensures no local extremums are added
* between the dataset discrete points due to the interpolation.
* @see https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
*/
export function splineCurveMonotone(points: readonly MonotoneSplinePoint[], indexAxis?: 'x' | 'y'): void;

View File

@ -1,5 +1,4 @@
export * from './helpers.canvas';
export * from './helpers.curve';
export * from './helpers.dom';
export * from './helpers.options';
export * from './helpers.canvas';