From 9184fa436a82e4341708f955b7fb7393a56e42dd Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sun, 21 Feb 2021 12:16:15 -0500 Subject: [PATCH 1/3] Provide a chart-type specific definition for ParsedData --- types/index.esm.d.ts | 218 +++++++++++------- .../line_scriptable_parsed_data.ts | 14 ++ .../plugin.tooltip/tooltip_parsed_data.ts | 22 ++ .../tooltip_parsed_data_chart_defaults.ts | 16 ++ 4 files changed, 182 insertions(+), 88 deletions(-) create mode 100644 types/tests/controllers/line_scriptable_parsed_data.ts create mode 100644 types/tests/plugins/plugin.tooltip/tooltip_parsed_data.ts create mode 100644 types/tests/plugins/plugin.tooltip/tooltip_parsed_data_chart_defaults.ts diff --git a/types/index.esm.d.ts b/types/index.esm.d.ts index 5a4802179c3..e5ad7344ad2 100644 --- a/types/index.esm.d.ts +++ b/types/index.esm.d.ts @@ -38,14 +38,14 @@ export { ScriptableAndArrayOptions } from './scriptable'; -export interface ScriptableContext { +export interface ScriptableContext { + active: boolean; chart: Chart; - parsed: unknown[]; - raw: unknown[]; dataIndex: number; dataset: ChartDataset; datasetIndex: number; - active: boolean; + parsed: TParsedData; + raw: unknown; } export interface ParsingOptions { @@ -91,8 +91,8 @@ export interface ControllerDatasetOptions extends ParsingOptions { export interface BarControllerDatasetOptions extends ControllerDatasetOptions, - ScriptableAndArrayOptions, - ScriptableAndArrayOptions { + ScriptableAndArrayOptions>, + ScriptableAndArrayOptions> { /** * The ID of the x axis to plot this dataset on. */ @@ -150,8 +150,8 @@ export const BarController: ChartComponent & { export interface BubbleControllerDatasetOptions extends ControllerDatasetOptions, - ScriptableAndArrayOptions, - ScriptableAndArrayOptions {} + ScriptableAndArrayOptions>, + ScriptableAndArrayOptions> {} export interface BubbleDataPoint { /** @@ -178,10 +178,10 @@ export const BubbleController: ChartComponent & { export interface LineControllerDatasetOptions extends ControllerDatasetOptions, - ScriptableAndArrayOptions, - ScriptableAndArrayOptions, - ScriptableOptions, - ScriptableOptions { + ScriptableAndArrayOptions>, + ScriptableAndArrayOptions>, + ScriptableOptions>, + ScriptableOptions> { /** * The ID of the x axis to plot this dataset on. */ @@ -236,8 +236,8 @@ export const ScatterController: ChartComponent & { export interface DoughnutControllerDatasetOptions extends ControllerDatasetOptions, - ScriptableAndArrayOptions, - ScriptableAndArrayOptions { + ScriptableAndArrayOptions>, + ScriptableAndArrayOptions> { /** * Sweep to allow arcs to cover. @@ -354,10 +354,10 @@ export const PolarAreaController: ChartComponent & { export interface RadarControllerDatasetOptions extends ControllerDatasetOptions, - ScriptableOptions, - ScriptableOptions, - ScriptableOptions, - ScriptableOptions { + ScriptableOptions>, + ScriptableOptions>, + ScriptableOptions>, + ScriptableOptions> { /** * The ID of the x axis to plot this dataset on. */ @@ -520,7 +520,11 @@ export declare enum UpdateModeEnum { export type UpdateMode = keyof typeof UpdateModeEnum; -export class DatasetController { +export class DatasetController< + TElement extends Element = Element, + TDatasetElement extends Element = Element, + TParsedData = unknown, +> { constructor(chart: Chart, datasetIndex: number); readonly chart: Chart; @@ -577,7 +581,7 @@ export class DatasetController, data: AnyObject[], start: number, count: number): AnyObject[]; protected parseArrayData(meta: ChartMeta, data: AnyObject[], start: number, count: number): AnyObject[]; protected parseObjectData(meta: ChartMeta, data: AnyObject[], start: number, count: number): AnyObject[]; - protected getParsed(index: number): AnyObject; + protected getParsed(index: number): TParsedData; protected applyStack(scale: Scale, parsed: unknown[]): number; protected updateRangeFromParsed( range: { min: number; max: number }, @@ -595,12 +599,14 @@ export interface DatasetControllerChartComponent extends ChartComponent { }; } -export interface Defaults extends CoreChartOptions, ElementChartOptions, PluginChartOptions { +// TParsedData defaults to unknown because global defaults are for any chart +// type, thus the data type can be many different possible values. +export interface Defaults extends CoreChartOptions, ElementChartOptions, PluginChartOptions { controllers: { [key in ChartType]: DeepPartial< - CoreChartOptions & + CoreChartOptions & ElementChartOptions & - PluginChartOptions & + PluginChartOptions & DatasetChartOptions[key] & ScaleChartOptions & ChartTypeRegistry[key]['chartOptions'] @@ -730,7 +736,8 @@ export const layouts: { update(chart: Chart, width: number, height: number): void; }; -export interface Plugin extends ExtendedPlugin { +// TParsedData defaults to unknown here since plugins can work for any chart type +export interface Plugin extends ExtendedPlugin { id: string; /** @@ -1335,9 +1342,9 @@ export interface HoverInteractionOptions extends CoreInteractionOptions { onHover(event: ChartEvent, elements: ActiveElement[], chart: Chart): void; } -export interface CoreChartOptions extends ParsingOptions, AnimationOptions { +export interface CoreChartOptions extends ParsingOptions, AnimationOptions { - datasets: AnimationOptions; + datasets: AnimationOptions; /** * The base axis of the chart. 'x' for vertical charts and 'y' for horizontal charts. @@ -1420,7 +1427,7 @@ export interface CoreChartOptions extends ParsingOptions, AnimationOptions { onClick(event: ChartEvent, elements: ActiveElement[], chart: Chart): void; layout: { - padding: Scriptable; + padding: Scriptable>; }; } @@ -1457,39 +1464,39 @@ export type EasingFunction = | 'easeOutBounce' | 'easeInOutBounce'; -export type AnimationSpec = { +export type AnimationSpec = { /** * The number of milliseconds an animation takes. * @default 1000 */ - duration: Scriptable; + duration: Scriptable>; /** * Easing function to use * @default 'easeOutQuart' */ - easing: Scriptable; + easing: Scriptable>; /** * Running animation count + FPS display in upper left corner of the chart. * @default false */ - debug: Scriptable; + debug: Scriptable>; /** * Delay before starting the animations. * @default 0 */ - delay: Scriptable; + delay: Scriptable>; /** * If set to true, the animations loop endlessly. * @default false */ - loop: Scriptable; + loop: Scriptable>; } -export type AnimationsSpec = { - [name: string]: false | AnimationSpec & { +export type AnimationsSpec = { + [name: string]: false | AnimationSpec & { properties: string[]; /** @@ -1502,25 +1509,25 @@ export type AnimationsSpec = { /** * Start value for the animation. Current value is used when undefined */ - from: Scriptable; + from: Scriptable>; /** * */ - to: Scriptable; + to: Scriptable>; } } -export type TransitionSpec = { - animation: AnimationSpec; - animations: AnimationsSpec; +export type TransitionSpec = { + animation: AnimationSpec; + animations: AnimationsSpec; } -export type TransitionsSpec = { - [mode: string]: TransitionSpec +export type TransitionsSpec = { + [mode: string]: TransitionSpec } -export type AnimationOptions = { - animation: false | AnimationSpec & { +export type AnimationOptions = { + animation: false | AnimationSpec & { /** * Callback called on each step of an animation. */ @@ -1530,8 +1537,8 @@ export type AnimationOptions = { */ onComplete: (this: Chart, event: AnimationEvent) => void; }; - animations: AnimationsSpec; - transitions: TransitionsSpec; + animations: AnimationsSpec; + transitions: TransitionsSpec; }; export interface FontSpec { @@ -2190,9 +2197,9 @@ export interface TitleOptions { export type TooltipAlignment = 'start' | 'center' | 'end'; -export interface TooltipModel { +export interface TooltipModel { // The items that we are rendering in the tooltip. See Tooltip Item Interface section - dataPoints: TooltipItem[]; + dataPoints: TooltipItem[]; // Positioning xAlign: TooltipAlignment; @@ -2236,7 +2243,7 @@ export interface TooltipModel { opacity: number; // tooltip options - options: TooltipOptions; + options: TooltipOptions; } export const Tooltip: Plugin & { @@ -2248,28 +2255,28 @@ export const Tooltip: Plugin & { setActiveElements(active: ActiveDataPoint[], eventPosition: { x: number, y: number }): void; }; -export interface TooltipCallbacks { - beforeTitle(this: TooltipModel, tooltipItems: TooltipItem[]): string | string[]; - title(this: TooltipModel, tooltipItems: TooltipItem[]): string | string[]; - afterTitle(this: TooltipModel, tooltipItems: TooltipItem[]): string | string[]; +export interface TooltipCallbacks { + beforeTitle(this: TooltipModel, tooltipItems: TooltipItem[]): string | string[]; + title(this: TooltipModel, tooltipItems: TooltipItem[]): string | string[]; + afterTitle(this: TooltipModel, tooltipItems: TooltipItem[]): string | string[]; - beforeBody(this: TooltipModel, tooltipItems: TooltipItem[]): string | string[]; - afterBody(this: TooltipModel, tooltipItems: TooltipItem[]): string | string[]; + beforeBody(this: TooltipModel, tooltipItems: TooltipItem[]): string | string[]; + afterBody(this: TooltipModel, tooltipItems: TooltipItem[]): string | string[]; - beforeLabel(this: TooltipModel, tooltipItem: TooltipItem): string | string[]; - label(this: TooltipModel, tooltipItem: TooltipItem): string | string[]; - afterLabel(this: TooltipModel, tooltipItem: TooltipItem): string | string[]; + beforeLabel(this: TooltipModel, tooltipItem: TooltipItem): string | string[]; + label(this: TooltipModel, tooltipItem: TooltipItem): string | string[]; + afterLabel(this: TooltipModel, tooltipItem: TooltipItem): string | string[]; - labelColor(this: TooltipModel, tooltipItem: TooltipItem): { borderColor: Color; backgroundColor: Color }; - labelTextColor(this: TooltipModel, tooltipItem: TooltipItem): Color; - labelPointStyle(this: TooltipModel, tooltipItem: TooltipItem): { pointStyle: PointStyle; rotation: number }; + labelColor(this: TooltipModel, tooltipItem: TooltipItem): { borderColor: Color; backgroundColor: Color }; + labelTextColor(this: TooltipModel, tooltipItem: TooltipItem): Color; + labelPointStyle(this: TooltipModel, tooltipItem: TooltipItem): { pointStyle: PointStyle; rotation: number }; - beforeFooter(this: TooltipModel, tooltipItems: TooltipItem[]): string | string[]; - footer(this: TooltipModel, tooltipItems: TooltipItem[]): string | string[]; - afterFooter(this: TooltipModel, tooltipItems: TooltipItem[]): string | string[]; + beforeFooter(this: TooltipModel, tooltipItems: TooltipItem[]): string | string[]; + footer(this: TooltipModel, tooltipItems: TooltipItem[]): string | string[]; + afterFooter(this: TooltipModel, tooltipItems: TooltipItem[]): string | string[]; } -export interface ExtendedPlugin { +export interface ExtendedPlugin { /** * @desc Called before drawing the `tooltip`. If any plugin returns `false`, * the tooltip drawing is cancelled until another `render` is triggered. @@ -2279,7 +2286,7 @@ export interface ExtendedPlugin { * @param {object} options - The plugin options. * @returns {boolean} `false` to cancel the chart tooltip drawing. */ - beforeTooltipDraw?(chart: Chart, args: { tooltip: TooltipModel }, options: O): boolean | void; + beforeTooltipDraw?(chart: Chart, args: { tooltip: TooltipModel }, options: O): boolean | void; /** * @desc Called after drawing the `tooltip`. Note that this hook will not * be called if the tooltip drawing has been previously cancelled. @@ -2288,9 +2295,9 @@ export interface ExtendedPlugin { * @param {Tooltip} args.tooltip - The tooltip. * @param {object} options - The plugin options. */ - afterTooltipDraw?(chart: Chart, args: { tooltip: TooltipModel }, options: O): void; + afterTooltipDraw?(chart: Chart, args: { tooltip: TooltipModel }, options: O): void; } -export interface TooltipOptions extends CoreInteractionOptions { +export interface TooltipOptions extends CoreInteractionOptions { /** * Are on-canvas tooltips enabled? * @default true @@ -2299,7 +2306,7 @@ export interface TooltipOptions extends CoreInteractionOptions { /** * See custom tooltip section. */ - custom(this: TooltipModel, args: { chart: Chart; tooltip: TooltipModel }): void; + custom(this: TooltipModel, args: { chart: Chart; tooltip: TooltipModel }): void; /** * The mode for positioning the tooltip */ @@ -2314,9 +2321,9 @@ export interface TooltipOptions extends CoreInteractionOptions { /** * Sort tooltip items. */ - itemSort: (a: TooltipItem, b: TooltipItem) => number; + itemSort: (a: TooltipItem, b: TooltipItem) => number; - filter: (e: TooltipItem) => boolean; + filter: (e: TooltipItem) => boolean; /** * Background color of the tooltip. @@ -2464,14 +2471,12 @@ export interface TooltipOptions extends CoreInteractionOptions { */ textDirection: string; - animation: AnimationSpec; - - animations: AnimationsSpec; - - callbacks: TooltipCallbacks; + animation: AnimationSpec; + animations: AnimationsSpec; + callbacks: TooltipCallbacks; } -export interface TooltipItem { +export interface TooltipItem { /** * The chart the tooltip is being shown on */ @@ -2485,7 +2490,7 @@ export interface TooltipItem { /** * Parsed data values for the given `dataIndex` and `datasetIndex` */ - parsed: unknown; + parsed: TParsedData; /** * Raw data values for the given `dataIndex` and `datasetIndex` @@ -2518,15 +2523,15 @@ export interface TooltipItem { element: Element; } -export interface PluginOptionsByType { +export interface PluginOptionsByType { decimation: DecimationOptions; filler: FillerOptions; legend: LegendOptions; title: TitleOptions; - tooltip: TooltipOptions; + tooltip: TooltipOptions; } -export interface PluginChartOptions { - plugins: Partial; +export interface PluginChartOptions { + plugins: Partial>; } export interface GridLineOptions { @@ -3113,53 +3118,87 @@ export interface ScaleTypeRegistry extends CartesianScaleTypeRegistry, RadialSca export type ScaleType = keyof ScaleTypeRegistry; +interface CartesianParsedData { + x: number; + y: number; +} + +interface BarParsedData extends CartesianParsedData { + // Only specified if floating bars are show + _custom?: { + barStart: number; + barEnd: number; + start: number; + end: number; + min: number; + max: number; + } +} + +interface BubbleParsedData extends CartesianParsedData { + // The bubble radius value + _custom: number; +} + +interface RadialParsedData { + r: number; +} + export interface ChartTypeRegistry { bar: { chartOptions: BarControllerChartOptions; datasetOptions: BarControllerDatasetOptions; defaultDataPoint: number; + parsedDataType: BarParsedData, scales: keyof CartesianScaleTypeRegistry; }; line: { chartOptions: LineControllerChartOptions; datasetOptions: LineControllerDatasetOptions & FillerControllerDatasetOptions; defaultDataPoint: ScatterDataPoint; + parsedDataType: CartesianParsedData; scales: keyof CartesianScaleTypeRegistry; }; scatter: { chartOptions: ScatterControllerChartOptions; datasetOptions: ScatterControllerDatasetOptions; defaultDataPoint: ScatterDataPoint; + parsedDataType: CartesianParsedData; scales: keyof CartesianScaleTypeRegistry; }; bubble: { chartOptions: EmptyObject; datasetOptions: BubbleControllerDatasetOptions; defaultDataPoint: BubbleDataPoint; + parsedDataType: BubbleParsedData; scales: keyof CartesianScaleTypeRegistry; }; pie: { chartOptions: PieControllerChartOptions; datasetOptions: PieControllerDatasetOptions; defaultDataPoint: PieDataPoint; + parsedDataType: number; scales: keyof CartesianScaleTypeRegistry; }; doughnut: { chartOptions: DoughnutControllerChartOptions; datasetOptions: DoughnutControllerDatasetOptions; defaultDataPoint: DoughnutDataPoint; + parsedDataType: number; scales: keyof CartesianScaleTypeRegistry; }; polarArea: { chartOptions: PolarAreaControllerChartOptions; datasetOptions: PolarAreaControllerDatasetOptions; defaultDataPoint: number; + parsedDataType: RadialParsedData; scales: keyof RadialScaleTypeRegistry; }; radar: { chartOptions: RadarControllerChartOptions; datasetOptions: RadarControllerDatasetOptions; defaultDataPoint: number; + parsedDataType: RadialParsedData; scales: keyof RadialScaleTypeRegistry; }; } @@ -3182,10 +3221,10 @@ export type ScaleChartOptions = { }; }; -export type ChartOptions = DeepPartial< - CoreChartOptions & +export type ChartOptions = DeepPartial< + CoreChartOptions & ElementChartOptions & - PluginChartOptions & + PluginChartOptions & DatasetChartOptions & ScaleChartOptions & ChartTypeRegistry[TType]['chartOptions'] @@ -3195,6 +3234,8 @@ export type DefaultDataPoint = ChartType extends TType ChartTypeRegistry[TType]['defaultDataPoint'] >; +export type ParsedDataType = ChartType extends TType ? unknown : ChartTypeRegistry[TType]['parsedDataType']; + export interface ChartDatasetProperties { type?: TType; data: TData; @@ -3210,7 +3251,7 @@ export type ChartDataset< export interface ChartData< TType extends ChartType = ChartType, TData extends unknown[] = DefaultDataPoint, - TLabel = unknown + TLabel = unknown, > { labels: TLabel[]; datasets: ChartDataset[]; @@ -3219,10 +3260,11 @@ export interface ChartData< export interface ChartConfiguration< TType extends ChartType = ChartType, TData extends unknown[] = DefaultDataPoint, - TLabel = unknown + TLabel = unknown, + TParsedData extends unknown = ParsedDataType, > { type: TType; data: ChartData; - options?: ChartOptions; + options?: ChartOptions; plugins?: Plugin[]; } diff --git a/types/tests/controllers/line_scriptable_parsed_data.ts b/types/tests/controllers/line_scriptable_parsed_data.ts new file mode 100644 index 00000000000..da88d0ec2b5 --- /dev/null +++ b/types/tests/controllers/line_scriptable_parsed_data.ts @@ -0,0 +1,14 @@ +import { Chart } from '../../index.esm'; + +const chart = new Chart('id', { + type: 'line', + data: { + labels: [], + datasets: [{ + data: [], + backgroundColor: (context) => { + return context.parsed.y > 10 ? 'green' : 'red'; + } + }] + }, +}); diff --git a/types/tests/plugins/plugin.tooltip/tooltip_parsed_data.ts b/types/tests/plugins/plugin.tooltip/tooltip_parsed_data.ts new file mode 100644 index 00000000000..93b7a9004ba --- /dev/null +++ b/types/tests/plugins/plugin.tooltip/tooltip_parsed_data.ts @@ -0,0 +1,22 @@ +import { Chart } from '../../../index.esm'; + +const chart = new Chart('id', { + type: 'bar', + data: { + labels: [], + datasets: [{ + data: [] + }] + }, + options: { + plugins: { + tooltip: { + callbacks: { + label: (item) => { + return `Foo data ${item.parsed.y}`; + } + } + } + } + }, +}); diff --git a/types/tests/plugins/plugin.tooltip/tooltip_parsed_data_chart_defaults.ts b/types/tests/plugins/plugin.tooltip/tooltip_parsed_data_chart_defaults.ts new file mode 100644 index 00000000000..c5c37adddab --- /dev/null +++ b/types/tests/plugins/plugin.tooltip/tooltip_parsed_data_chart_defaults.ts @@ -0,0 +1,16 @@ +import { Chart } from '../../../index.esm'; + +Chart.defaults.controllers.bubble.plugins.tooltip.callbacks.label = (item) => { + const {x, y, _custom: r} = item.parsed; + return `${item.label}: (${x}, ${y}, ${r})`; +} + +const chart = new Chart('id', { + type: 'bubble', + data: { + labels: [], + datasets: [{ + data: [] + }] + }, +}); From 8a4388f41f8d5c43e5ba783d9819db2e06e89fdd Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sun, 21 Feb 2021 12:44:59 -0500 Subject: [PATCH 2/3] Fix lint error --- types/index.esm.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/index.esm.d.ts b/types/index.esm.d.ts index e5ad7344ad2..d0a916e69d1 100644 --- a/types/index.esm.d.ts +++ b/types/index.esm.d.ts @@ -2471,8 +2471,8 @@ export interface TooltipOptions extends CoreInteractionOptions { */ textDirection: string; - animation: AnimationSpec; - animations: AnimationsSpec; + animation: AnimationSpec; + animations: AnimationsSpec; callbacks: TooltipCallbacks; } From 8564da35309b2904d39f4ab67f96c9395c11944c Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sun, 21 Feb 2021 12:59:25 -0500 Subject: [PATCH 3/3] Code review feedback --- types/index.esm.d.ts | 2 +- types/tests/tsconfig.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/types/index.esm.d.ts b/types/index.esm.d.ts index d0a916e69d1..1d237d90afb 100644 --- a/types/index.esm.d.ts +++ b/types/index.esm.d.ts @@ -3251,7 +3251,7 @@ export type ChartDataset< export interface ChartData< TType extends ChartType = ChartType, TData extends unknown[] = DefaultDataPoint, - TLabel = unknown, + TLabel = unknown > { labels: TLabel[]; datasets: ChartDataset[]; diff --git a/types/tests/tsconfig.json b/types/tests/tsconfig.json index 774512d1992..2c18b014b0f 100644 --- a/types/tests/tsconfig.json +++ b/types/tests/tsconfig.json @@ -6,7 +6,7 @@ "noEmit": true }, "include": [ - "*.ts", + "./**/*.ts", "../index.esm.d.ts" ] }