refactor: move batch of helpers to ts (#10722)

* refactor: move batch of helpers to ts

* refactor: review fixes
This commit is contained in:
Dan Onoshko
2022-09-30 20:48:12 +07:00
committed by GitHub
parent 52cf8e8a94
commit d1e118aea8
19 changed files with 204 additions and 240 deletions

View File

@@ -7,6 +7,11 @@ const interpolators = {
boolean(from, to, factor) {
return factor > 0.5 ? to : from;
},
/**
* @param {string} from
* @param {string} to
* @param {number} factor
*/
color(from, to, factor) {
const c0 = helpersColor(from || transparent);
const c1 = c0.valid && helpersColor(to || transparent);

View File

@@ -1030,31 +1030,19 @@ export default class DatasetController {
this.chart._dataChanges.push([this.index, ...args]);
}
/**
* @private
*/
_onDataPush() {
const count = arguments.length;
this._sync(['_insertElements', this.getDataset().data.length - count, count]);
}
/**
* @private
*/
_onDataPop() {
this._sync(['_removeElements', this._cachedMeta.data.length - 1, 1]);
}
/**
* @private
*/
_onDataShift() {
this._sync(['_removeElements', 0, 1]);
}
/**
* @private
*/
_onDataSplice(start, count) {
if (count) {
this._sync(['_removeElements', start, count]);
@@ -1065,9 +1053,6 @@ export default class DatasetController {
}
}
/**
* @private
*/
_onDataUnshift() {
this._sync(['_insertElements', 0, arguments.length]);
}

View File

@@ -4,6 +4,7 @@ import {PI, _isBetween, _limitValue} from '../helpers/helpers.math';
import {_readValueToProps} from '../helpers/helpers.options';
/** @typedef {{ x: number, y: number, startAngle: number, endAngle: number, innerRadius: number, outerRadius: number, circumference: number }} ArcProps */
/** @typedef {import('../../types/geometric').Point} Point */
function clipArc(ctx, element, endAngle) {
const {startAngle, pixelMargin, x, y, outerRadius, innerRadius} = element;
@@ -310,7 +311,7 @@ export default class ArcElement extends Element {
* @param {boolean} [useFinalPosition]
*/
inRange(chartX, chartY, useFinalPosition) {
const point = this.getProps(['x', 'y'], useFinalPosition);
const point = /** @type {Point} */ (this.getProps(['x', 'y'], useFinalPosition));
const {angle, distance} = getAngleFromPoint(point, {x: chartX, y: chartY});
const {startAngle, endAngle, innerRadius, outerRadius, circumference} = /** @type {ArcProps} */ (this.getProps([
'startAngle',

View File

@@ -2,16 +2,30 @@ import {_capitalize} from './helpers.core';
/**
* Binary search
* @param {array} table - the table search. must be sorted!
* @param {number} value - value to find
* @param {function} [cmp]
* @param table - the table search. must be sorted!
* @param value - value to find
* @param cmp
* @private
*/
export function _lookup(table, value, cmp) {
export function _lookup(
table: number[],
value: number,
cmp?: (value: number) => boolean
): {lo: number, hi: number};
export function _lookup<T>(
table: T[],
value: number,
cmp: (value: number) => boolean
): {lo: number, hi: number};
export function _lookup(
table: unknown[],
value: number,
cmp?: (value: number) => boolean
) {
cmp = cmp || ((index) => table[index] < value);
let hi = table.length - 1;
let lo = 0;
let mid;
let mid: number;
while (hi - lo > 1) {
mid = (lo + hi) >> 1;
@@ -27,13 +41,18 @@ export function _lookup(table, value, cmp) {
/**
* Binary search
* @param {array} table - the table search. must be sorted!
* @param {string} key - property name for the value in each entry
* @param {number} value - value to find
* @param {boolean} [last] - lookup last index
* @param table - the table search. must be sorted!
* @param key - property name for the value in each entry
* @param value - value to find
* @param last - lookup last index
* @private
*/
export const _lookupByKey = (table, key, value, last) =>
export const _lookupByKey = (
table: Record<string, number>[],
key: string,
value: number,
last?: boolean
) =>
_lookup(table, value, last
? index => {
const ti = table[index][key];
@@ -43,22 +62,26 @@ export const _lookupByKey = (table, key, value, last) =>
/**
* Reverse binary search
* @param {array} table - the table search. must be sorted!
* @param {string} key - property name for the value in each entry
* @param {number} value - value to find
* @param table - the table search. must be sorted!
* @param key - property name for the value in each entry
* @param value - value to find
* @private
*/
export const _rlookupByKey = (table, key, value) =>
export const _rlookupByKey = (
table: Record<string, number>[],
key: string,
value: number
) =>
_lookup(table, value, index => table[index][key] >= value);
/**
* Return subset of `values` between `min` and `max` inclusive.
* Values are assumed to be in sorted order.
* @param {number[]} values - sorted array of values
* @param {number} min - min value
* @param {number} max - max value
* @param values - sorted array of values
* @param min - min value
* @param max - max value
*/
export function _filterBetween(values, min, max) {
export function _filterBetween(values: number[], min: number, max: number) {
let start = 0;
let end = values.length;
@@ -74,13 +97,22 @@ export function _filterBetween(values, min, max) {
: values;
}
const arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift'];
const arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift'] as const;
export interface ArrayListener<T> {
_onDataPush?(...item: T[]): void;
_onDataPop?(): void;
_onDataShift?(): void;
_onDataSplice?(index: number, deleteCount: number, ...items: T[]): void;
_onDataUnshift?(...item: T[]): void;
}
/**
* Hooks the array methods that add or remove values ('push', pop', 'shift', 'splice',
* 'unshift') and notify the listener AFTER the array has been altered. Listeners are
* called on the '_onData*' callbacks (e.g. _onDataPush, etc.) with same arguments.
*/
export function listenArrayEvents<T>(array: T[], listener: ArrayListener<T>): void;
export function listenArrayEvents(array, listener) {
if (array._chartjs) {
array._chartjs.listeners.push(listener);
@@ -122,6 +154,7 @@ export function listenArrayEvents(array, listener) {
* Removes the given array event listener and cleanup extra attached properties (such as
* the _chartjs stub and overridden methods) if array doesn't have any more listeners.
*/
export function unlistenArrayEvents<T>(array: T[], listener: ArrayListener<T>): void;
export function unlistenArrayEvents(array, listener) {
const stub = array._chartjs;
if (!stub) {
@@ -146,11 +179,11 @@ export function unlistenArrayEvents(array, listener) {
}
/**
* @param {Array} items
* @param items
*/
export function _arrayUnique(items) {
const set = new Set();
let i, ilen;
export function _arrayUnique<T>(items: T[]) {
const set = new Set<T>();
let i: number, ilen: number;
for (i = 0, ilen = items.length; i < ilen; ++i) {
set.add(items[i]);

View File

@@ -1,20 +0,0 @@
import colorLib from '@kurkle/color';
export function isPatternOrGradient(value) {
if (value && typeof value === 'object') {
const type = value.toString();
return type === '[object CanvasPattern]' || type === '[object CanvasGradient]';
}
return false;
}
export function color(value) {
return isPatternOrGradient(value) ? value : colorLib(value);
}
export function getHoverColor(value) {
return isPatternOrGradient(value)
? value
: colorLib(value).saturate(0.5).darken(0.1).hexString();
}

View File

@@ -0,0 +1,32 @@
import colorLib, {Color} from '@kurkle/color';
export function isPatternOrGradient(value: unknown): value is CanvasPattern | CanvasGradient {
if (value && typeof value === 'object') {
const type = value.toString();
return type === '[object CanvasPattern]' || type === '[object CanvasGradient]';
}
return false;
}
export function color(value: CanvasGradient): CanvasGradient;
export function color(value: CanvasPattern): CanvasPattern;
export function color(
value:
| string
| { r: number; g: number; b: number; a: number }
| [number, number, number]
| [number, number, number, number]
): Color;
export function color(value) {
return isPatternOrGradient(value) ? value : colorLib(value);
}
export function getHoverColor(value: CanvasGradient): CanvasGradient;
export function getHoverColor(value: CanvasPattern): CanvasPattern;
export function getHoverColor(value: string): string;
export function getHoverColor(value) {
return isPatternOrGradient(value)
? value
: colorLib(value).saturate(0.5).darken(0.1).hexString();
}

View File

@@ -1,35 +0,0 @@
/**
* @private
*/
export function _pointInLine(p1, p2, t, mode) { // eslint-disable-line no-unused-vars
return {
x: p1.x + t * (p2.x - p1.x),
y: p1.y + t * (p2.y - p1.y)
};
}
/**
* @private
*/
export function _steppedInterpolation(p1, p2, t, mode) {
return {
x: p1.x + t * (p2.x - p1.x),
y: mode === 'middle' ? t < 0.5 ? p1.y : p2.y
: mode === 'after' ? t < 1 ? p1.y : p2.y
: t > 0 ? p2.y : p1.y
};
}
/**
* @private
*/
export function _bezierInterpolation(p1, p2, t, mode) { // eslint-disable-line 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);
const b = _pointInLine(cp1, cp2, t);
const c = _pointInLine(cp2, p2, t);
const d = _pointInLine(a, b, t);
const e = _pointInLine(b, c, t);
return _pointInLine(d, e, t);
}

View File

@@ -0,0 +1,42 @@
import type {Point} from '../../types/geometric';
import type {MonotoneSplinePoint} from '../../types/helpers';
/**
* @private
*/
export function _pointInLine(p1: Point, p2: Point, t: number, mode?) { // eslint-disable-line @typescript-eslint/no-unused-vars
return {
x: p1.x + t * (p2.x - p1.x),
y: p1.y + t * (p2.y - p1.y)
};
}
/**
* @private
*/
export function _steppedInterpolation(
p1: Point,
p2: Point,
t: number, mode: 'middle' | 'after' | unknown
) {
return {
x: p1.x + t * (p2.x - p1.x),
y: mode === 'middle' ? t < 0.5 ? p1.y : p2.y
: mode === 'after' ? t < 1 ? p1.y : p2.y
: t > 0 ? p2.y : p1.y
};
}
/**
* @private
*/
export function _bezierInterpolation(p1: MonotoneSplinePoint, p2: MonotoneSplinePoint, 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);
const b = _pointInLine(cp1, cp2, t);
const c = _pointInLine(cp2, p2, t);
const d = _pointInLine(a, b, t);
const e = _pointInLine(b, c, t);
return _pointInLine(d, e, t);
}

View File

@@ -1,7 +1,7 @@
const intlCache = new Map();
const intlCache = new Map<string, Intl.NumberFormat>();
function getNumberFormat(locale, options) {
function getNumberFormat(locale: string, options?: Intl.NumberFormatOptions) {
options = options || {};
const cacheKey = locale + JSON.stringify(options);
let formatter = intlCache.get(cacheKey);
@@ -12,6 +12,6 @@ function getNumberFormat(locale, options) {
return formatter;
}
export function formatNumber(num, locale, options) {
export function formatNumber(num: number, locale: string, options?: Intl.NumberFormatOptions) {
return getNumberFormat(locale, options).format(num);
}

View File

@@ -1,3 +1,4 @@
import type {Point} from '../../types/geometric';
import {isFinite as isFiniteNumber} from './helpers.core';
/**
@@ -17,11 +18,14 @@ export const TWO_THIRDS_PI = PI * 2 / 3;
export const log10 = Math.log10;
export const sign = Math.sign;
export function almostEquals(x: number, y: number, epsilon: number) {
return Math.abs(x - y) < epsilon;
}
/**
* Implementation of the nice number algorithm used in determining where axis labels will go
* @return {number}
*/
export function niceNum(range) {
export function niceNum(range: number) {
const roundedRange = Math.round(range);
range = almostEquals(range, roundedRange, range / 1000) ? roundedRange : range;
const niceRange = Math.pow(10, Math.floor(log10(range)));
@@ -34,10 +38,10 @@ export function niceNum(range) {
* Returns an array of factors sorted from 1 to sqrt(value)
* @private
*/
export function _factorize(value) {
const result = [];
export function _factorize(value: number) {
const result: number[] = [];
const sqrt = Math.sqrt(value);
let i;
let i: number;
for (i = 1; i < sqrt; i++) {
if (value % i === 0) {
@@ -53,15 +57,11 @@ export function _factorize(value) {
return result;
}
export function isNumber(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
export function isNumber(n: unknown): n is number {
return !isNaN(parseFloat(n as string)) && isFinite(n as number);
}
export function almostEquals(x, y, epsilon) {
return Math.abs(x - y) < epsilon;
}
export function almostWhole(x, epsilon) {
export function almostWhole(x: number, epsilon: number) {
const rounded = Math.round(x);
return ((rounded - epsilon) <= x) && ((rounded + epsilon) >= x);
}
@@ -69,8 +69,12 @@ export function almostWhole(x, epsilon) {
/**
* @private
*/
export function _setMinAndMaxByKey(array, target, property) {
let i, ilen, value;
export function _setMinAndMaxByKey(
array: Record<string, number>[],
target: { min: number, max: number },
property: string
) {
let i: number, ilen: number, value: number;
for (i = 0, ilen = array.length; i < ilen; i++) {
value = array[i][property];
@@ -81,22 +85,22 @@ export function _setMinAndMaxByKey(array, target, property) {
}
}
export function toRadians(degrees) {
export function toRadians(degrees: number) {
return degrees * (PI / 180);
}
export function toDegrees(radians) {
export function toDegrees(radians: number) {
return radians * (180 / PI);
}
/**
* Returns the number of decimal places
* i.e. the number of digits after the decimal point, of the value of this Number.
* @param {number} x - A number.
* @returns {number} The number of decimal places.
* @param x - A number.
* @returns The number of decimal places.
* @private
*/
export function _decimalPlaces(x) {
export function _decimalPlaces(x: number) {
if (!isFiniteNumber(x)) {
return;
}
@@ -110,7 +114,10 @@ export function _decimalPlaces(x) {
}
// Gets the angle from vertical upright to the point about a centre.
export function getAngleFromPoint(centrePoint, anglePoint) {
export function getAngleFromPoint(
centrePoint: Point,
anglePoint: Point
) {
const distanceFromXCenter = anglePoint.x - centrePoint.x;
const distanceFromYCenter = anglePoint.y - centrePoint.y;
const radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
@@ -127,7 +134,7 @@ export function getAngleFromPoint(centrePoint, anglePoint) {
};
}
export function distanceBetweenPoints(pt1, pt2) {
export function distanceBetweenPoints(pt1: Point, pt2: Point) {
return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
}
@@ -135,7 +142,7 @@ export function distanceBetweenPoints(pt1, pt2) {
* Shortest distance between angles, in either direction.
* @private
*/
export function _angleDiff(a, b) {
export function _angleDiff(a: number, b: number) {
return (a - b + PITAU) % TAU - PI;
}
@@ -143,14 +150,14 @@ export function _angleDiff(a, b) {
* Normalize angle to be between 0 and 2*PI
* @private
*/
export function _normalizeAngle(a) {
export function _normalizeAngle(a: number) {
return (a % TAU + TAU) % TAU;
}
/**
* @private
*/
export function _angleBetween(angle, start, end, sameAngleIsFullCircle) {
export function _angleBetween(angle: number, start: number, end: number, sameAngleIsFullCircle?: boolean) {
const a = _normalizeAngle(angle);
const s = _normalizeAngle(start);
const e = _normalizeAngle(end);
@@ -164,12 +171,12 @@ export function _angleBetween(angle, start, end, sameAngleIsFullCircle) {
/**
* Limit `value` between `min` and `max`
* @param {number} value
* @param {number} min
* @param {number} max
* @param value
* @param min
* @param max
* @private
*/
export function _limitValue(value, min, max) {
export function _limitValue(value: number, min: number, max: number) {
return Math.max(min, Math.min(max, value));
}
@@ -177,17 +184,17 @@ export function _limitValue(value, min, max) {
* @param {number} value
* @private
*/
export function _int16Range(value) {
export function _int16Range(value: number) {
return _limitValue(value, -32768, 32767);
}
/**
* @param {number} value
* @param {number} start
* @param {number} end
* @param {number} [epsilon]
* @param value
* @param start
* @param end
* @param [epsilon]
* @private
*/
export function _isBetween(value, start, end, epsilon = 1e-6) {
export function _isBetween(value: number, start: number, end: number, epsilon = 1e-6) {
return value >= Math.min(start, end) - epsilon && value <= Math.max(start, end) + epsilon;
}

View File

@@ -1,4 +1,12 @@
const getRightToLeftAdapter = function(rectX, width) {
export interface RTLAdapter {
x(x: number): number;
setWidth(w: number): void;
textAlign(align: 'center' | 'left' | 'right'): 'center' | 'left' | 'right';
xPlus(x: number, value: number): number;
leftForLtr(x: number, itemWidth: number): number;
}
const getRightToLeftAdapter = function(rectX: number, width: number): RTLAdapter {
return {
x(x) {
return rectX + rectX + width - x;
@@ -21,7 +29,7 @@ const getRightToLeftAdapter = function(rectX, width) {
};
};
const getLeftToRightAdapter = function() {
const getLeftToRightAdapter = function(): RTLAdapter {
return {
x(x) {
return x;
@@ -34,18 +42,18 @@ const getLeftToRightAdapter = function() {
xPlus(x, value) {
return x + value;
},
leftForLtr(x, _itemWidth) { // eslint-disable-line no-unused-vars
leftForLtr(x, _itemWidth) { // eslint-disable-line @typescript-eslint/no-unused-vars
return x;
},
};
};
export function getRtlAdapter(rtl, rectX, width) {
export function getRtlAdapter(rtl: boolean, rectX: number, width: number) {
return rtl ? getRightToLeftAdapter(rectX, width) : getLeftToRightAdapter();
}
export function overrideTextDirection(ctx, direction) {
let style, original;
export function overrideTextDirection(ctx: CanvasRenderingContext2D, direction: 'ltr' | 'rtl') {
let style: CSSStyleDeclaration, original: [string, string];
if (direction === 'ltr' || direction === 'rtl') {
style = ctx.canvas.style;
original = [
@@ -54,13 +62,13 @@ export function overrideTextDirection(ctx, direction) {
];
style.setProperty('direction', direction, 'important');
ctx.prevTextDirection = original;
(ctx as { prevTextDirection?: [string, string] }).prevTextDirection = original;
}
}
export function restoreTextDirection(ctx, original) {
export function restoreTextDirection(ctx: CanvasRenderingContext2D, original?: [string, string]) {
if (original !== undefined) {
delete ctx.prevTextDirection;
delete (ctx as { prevTextDirection?: [string, string] }).prevTextDirection;
ctx.canvas.style.setProperty('direction', original[0], original[1]);
}
}

View File

@@ -4,6 +4,12 @@
*/
// export * from '.';
export * from './helpers.color';
export * from './helpers.collection';
export * from './helpers.core';
export * from './helpers.easing';
export * from './helpers.interpolation';
export * from './helpers.intl';
export * from './helpers.math';
export * from './helpers.rtl';
export * from '../../types/helpers';

View File

@@ -1,20 +0,0 @@
export interface ArrayListener<T> {
_onDataPush?(...item: T[]): void;
_onDataPop?(): void;
_onDataShift?(): void;
_onDataSplice?(index: number, deleteCount: number, ...items: T[]): void;
_onDataUnshift?(...item: T[]): void;
}
/**
* Hooks the array methods that add or remove values ('push', pop', 'shift', 'splice',
* 'unshift') and notify the listener AFTER the array has been altered. Listeners are
* called on the '_onData*' callbacks (e.g. _onDataPush, etc.) with same arguments.
*/
export function listenArrayEvents<T>(array: T[], listener: ArrayListener<T>): void;
/**
* Removes the given array event listener and cleanup extra attached properties (such as
* the _chartjs stub and overridden methods) if array doesn't have any more listeners.
*/
export function unlistenArrayEvents<T>(array: T[], listener: ArrayListener<T>): void;

View File

@@ -1,37 +0,0 @@
import { AnyObject } from '../basic';
export function color(value: CanvasGradient): CanvasGradient;
export function color(value: CanvasPattern): CanvasPattern;
export function color(
value:
| string
| { r: number; g: number; b: number; a: number }
| [number, number, number]
| [number, number, number, number]
): ColorModel;
export function isPatternOrGradient(value: unknown): value is CanvasPattern | CanvasGradient;
export interface ColorModel {
rgbString(): string;
hexString(): string;
hslString(): string;
rgb: { r: number; g: number; b: number; a: number };
valid: boolean;
mix(color: ColorModel, weight: number): this;
clone(): ColorModel;
alpha(a: number): ColorModel;
clearer(ration: number): ColorModel;
greyscale(): ColorModel;
opaquer(ratio: number): ColorModel;
negate(): ColorModel;
lighten(ratio: number): ColorModel;
darken(ratio: number): ColorModel;
saturate(ratio: number): ColorModel;
desaturate(ratio: number): ColorModel;
rotate(deg: number): this;
}
export function getHoverColor(value: CanvasGradient): CanvasGradient;
export function getHoverColor(value: CanvasPattern): CanvasPattern;
export function getHoverColor(value: string): string;

View File

@@ -1 +0,0 @@
export {};

View File

@@ -1,7 +0,0 @@
/**
* Format a number using a localized number formatter.
* @param num The number to format
* @param locale The locale to pass to the Intl.NumberFormat constructor
* @param options Number format options
*/
export function formatNumber(num: number, locale: string, options: Intl.NumberFormatOptions): string;

View File

@@ -1,17 +0,0 @@
export function log10(x: number): number;
export function isNumber(v: unknown): v is Number;
export function almostEquals(x: number, y: number, epsilon: number): boolean;
export function almostWhole(x: number, epsilon: number): number;
export function sign(x: number): number;
export function niceNum(range: number): number;
export function toRadians(degrees: number): number;
export function toDegrees(radians: number): number;
/**
* Gets the angle from vertical upright to the point about a centre.
*/
export function getAngleFromPoint(
centrePoint: { x: number; y: number },
anglePoint: { x: number; y: number }
): { angle: number; distance: number };
export function distanceBetweenPoints(pt1: { x: number; y: number }, pt2: { x: number; y: number }): number;

View File

@@ -1,12 +0,0 @@
export interface RTLAdapter {
x(x: number): number;
setWidth(w: number): void;
textAlign(align: 'center' | 'left' | 'right'): 'center' | 'left' | 'right';
xPlus(x: number, value: number): number;
leftForLtr(x: number, itemWidth: number): number;
}
export function getRtlAdapter(rtl: boolean, rectX: number, width: number): RTLAdapter;
export function overrideTextDirection(ctx: CanvasRenderingContext2D, direction: 'ltr' | 'rtl'): void;
export function restoreTextDirection(ctx: CanvasRenderingContext2D, original?: [string, string]): void;

View File

@@ -1,13 +1,7 @@
export * from './helpers.canvas';
export * from './helpers.collection';
export * from './helpers.color';
export * from './helpers.curve';
export * from './helpers.dom';
export * from './helpers.extras';
export * from './helpers.interpolation';
export * from './helpers.intl';
export * from './helpers.math';
export * from './helpers.options';
export * from './helpers.canvas';
export * from './helpers.rtl';
export * from './helpers.segment';