## Tooltip Callbacks
-Namespace: `options.plugins.tooltip.callbacks`, the tooltip has the following callbacks for providing text. For all functions, `this` will be the tooltip object created from the `Tooltip` constructor.
+Namespace: `options.plugins.tooltip.callbacks`, the tooltip has the following callbacks for providing text. For all functions, `this` will be the tooltip object created from the `Tooltip` constructor. If the callback returns `undefined`, then the default callback will be used. To remove things from the tooltip callback should return an empty string.
Namespace: `data.datasets[].tooltip.callbacks`, items marked with `Yes` in the column `Dataset override` can be overridden per dataset.
| Name | Arguments | Return Type | Dataset override | Description
| ---- | --------- | ----------- | ---------------- | -----------
-| `beforeTitle` | `TooltipItem[]` | `string | string[]` | | Returns the text to render before the title.
-| `title` | `TooltipItem[]` | `string | string[]` | | Returns text to render as the title of the tooltip.
-| `afterTitle` | `TooltipItem[]` | `string | string[]` | | Returns text to render after the title.
-| `beforeBody` | `TooltipItem[]` | `string | string[]` | | Returns text to render before the body section.
-| `beforeLabel` | `TooltipItem` | `string | string[]` | Yes | Returns text to render before an individual label. This will be called for each item in the tooltip.
-| `label` | `TooltipItem` | `string | string[]` | Yes | Returns text to render for an individual item in the tooltip. [more...](#label-callback)
-| `labelColor` | `TooltipItem` | `object` | Yes | Returns the colors to render for the tooltip item. [more...](#label-color-callback)
-| `labelTextColor` | `TooltipItem` | `Color` | Yes | Returns the colors for the text of the label for the tooltip item.
-| `labelPointStyle` | `TooltipItem` | `object` | Yes | Returns the point style to use instead of color boxes if usePointStyle is true (object with values `pointStyle` and `rotation`). Default implementation uses the point style from the dataset points. [more...](#label-point-style-callback)
-| `afterLabel` | `TooltipItem` | `string | string[]` | Yes | Returns text to render after an individual label.
-| `afterBody` | `TooltipItem[]` | `string | string[]` | | Returns text to render after the body section.
-| `beforeFooter` | `TooltipItem[]` | `string | string[]` | | Returns text to render before the footer section.
-| `footer` | `TooltipItem[]` | `string | string[]` | | Returns text to render as the footer of the tooltip.
-| `afterFooter` | `TooltipItem[]` | `string | string[]` | | Text to render after the footer section.
+| `beforeTitle` | `TooltipItem[]` | `string | string[] | undefined` | | Returns the text to render before the title.
+| `title` | `TooltipItem[]` | `string | string[] | undefined` | | Returns text to render as the title of the tooltip.
+| `afterTitle` | `TooltipItem[]` | `string | string[] | undefined` | | Returns text to render after the title.
+| `beforeBody` | `TooltipItem[]` | `string | string[] | undefined` | | Returns text to render before the body section.
+| `beforeLabel` | `TooltipItem` | `string | string[] | undefined` | Yes | Returns text to render before an individual label. This will be called for each item in the tooltip.
+| `label` | `TooltipItem` | `string | string[] | undefined` | Yes | Returns text to render for an individual item in the tooltip. [more...](#label-callback)
+| `labelColor` | `TooltipItem` | `object | undefined` | Yes | Returns the colors to render for the tooltip item. [more...](#label-color-callback)
+| `labelTextColor` | `TooltipItem` | `Color | undefined` | Yes | Returns the colors for the text of the label for the tooltip item.
+| `labelPointStyle` | `TooltipItem` | `object | undefined` | Yes | Returns the point style to use instead of color boxes if usePointStyle is true (object with values `pointStyle` and `rotation`). Default implementation uses the point style from the dataset points. [more...](#label-point-style-callback)
+| `afterLabel` | `TooltipItem` | `string | string[] | undefined` | Yes | Returns text to render after an individual label.
+| `afterBody` | `TooltipItem[]` | `string | string[] | undefined` | | Returns text to render after the body section.
+| `beforeFooter` | `TooltipItem[]` | `string | string[] | undefined` | | Returns text to render before the footer section.
+| `footer` | `TooltipItem[]` | `string | string[] | undefined` | | Returns text to render as the footer of the tooltip.
+| `afterFooter` | `TooltipItem[]` | `string | string[] | undefined` | | Text to render after the footer section.
### Label Callback
myCustomPositioner: TooltipPositionerFunction<ChartType>;
}
}
-```
\ No newline at end of file
+```
return override ? callbacks.override(override) : callbacks;
}
+const defaultCallbacks = {
+ // Args are: (tooltipItems, data)
+ beforeTitle: noop,
+ title(tooltipItems) {
+ if (tooltipItems.length > 0) {
+ const item = tooltipItems[0];
+ const labels = item.chart.data.labels;
+ const labelCount = labels ? labels.length : 0;
+
+ if (this && this.options && this.options.mode === 'dataset') {
+ return item.dataset.label || '';
+ } else if (item.label) {
+ return item.label;
+ } else if (labelCount > 0 && item.dataIndex < labelCount) {
+ return labels[item.dataIndex];
+ }
+ }
+
+ return '';
+ },
+ afterTitle: noop,
+
+ // Args are: (tooltipItems, data)
+ beforeBody: noop,
+
+ // Args are: (tooltipItem, data)
+ beforeLabel: noop,
+ label(tooltipItem) {
+ if (this && this.options && this.options.mode === 'dataset') {
+ return tooltipItem.label + ': ' + tooltipItem.formattedValue || tooltipItem.formattedValue;
+ }
+
+ let label = tooltipItem.dataset.label || '';
+
+ if (label) {
+ label += ': ';
+ }
+ const value = tooltipItem.formattedValue;
+ if (!isNullOrUndef(value)) {
+ label += value;
+ }
+ return label;
+ },
+ labelColor(tooltipItem) {
+ const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);
+ const options = meta.controller.getStyle(tooltipItem.dataIndex);
+ return {
+ borderColor: options.borderColor,
+ backgroundColor: options.backgroundColor,
+ borderWidth: options.borderWidth,
+ borderDash: options.borderDash,
+ borderDashOffset: options.borderDashOffset,
+ borderRadius: 0,
+ };
+ },
+ labelTextColor() {
+ return this.options.bodyColor;
+ },
+ labelPointStyle(tooltipItem) {
+ const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);
+ const options = meta.controller.getStyle(tooltipItem.dataIndex);
+ return {
+ pointStyle: options.pointStyle,
+ rotation: options.rotation,
+ };
+ },
+ afterLabel: noop,
+
+ // Args are: (tooltipItems, data)
+ afterBody: noop,
+
+ // Args are: (tooltipItems, data)
+ beforeFooter: noop,
+ footer: noop,
+ afterFooter: noop
+};
+
+/**
+ * Invoke callback from object with context and arguments.
+ * If callback returns `undefined`, then will be invoked default callback.
+ * @param {Record<keyof typeof defaultCallbacks, Function>} callbacks
+ * @param {keyof typeof defaultCallbacks} name
+ * @param {*} ctx
+ * @param {*} arg
+ * @returns {any}
+ */
+function invokeCallbackWithFallback(callbacks, name, ctx, arg) {
+ const result = callbacks[name].call(ctx, arg);
+
+ if (typeof result === 'undefined') {
+ return defaultCallbacks[name].call(ctx, arg);
+ }
+
+ return result;
+}
+
export class Tooltip extends Element {
/**
getTitle(context, options) {
const {callbacks} = options;
- const beforeTitle = callbacks.beforeTitle.apply(this, [context]);
- const title = callbacks.title.apply(this, [context]);
- const afterTitle = callbacks.afterTitle.apply(this, [context]);
+ const beforeTitle = invokeCallbackWithFallback(callbacks, 'beforeTitle', this, context);
+ const title = invokeCallbackWithFallback(callbacks, 'title', this, context);
+ const afterTitle = invokeCallbackWithFallback(callbacks, 'afterTitle', this, context);
let lines = [];
lines = pushOrConcat(lines, splitNewlines(beforeTitle));
}
getBeforeBody(tooltipItems, options) {
- return getBeforeAfterBodyLines(options.callbacks.beforeBody.apply(this, [tooltipItems]));
+ return getBeforeAfterBodyLines(
+ invokeCallbackWithFallback(options.callbacks, 'beforeBody', this, tooltipItems)
+ );
}
getBody(tooltipItems, options) {
after: []
};
const scoped = overrideCallbacks(callbacks, context);
- pushOrConcat(bodyItem.before, splitNewlines(scoped.beforeLabel.call(this, context)));
- pushOrConcat(bodyItem.lines, scoped.label.call(this, context));
- pushOrConcat(bodyItem.after, splitNewlines(scoped.afterLabel.call(this, context)));
+ pushOrConcat(bodyItem.before, splitNewlines(invokeCallbackWithFallback(scoped, 'beforeLabel', this, context)));
+ pushOrConcat(bodyItem.lines, invokeCallbackWithFallback(scoped, 'label', this, context));
+ pushOrConcat(bodyItem.after, splitNewlines(invokeCallbackWithFallback(scoped, 'afterLabel', this, context)));
bodyItems.push(bodyItem);
});
}
getAfterBody(tooltipItems, options) {
- return getBeforeAfterBodyLines(options.callbacks.afterBody.apply(this, [tooltipItems]));
+ return getBeforeAfterBodyLines(
+ invokeCallbackWithFallback(options.callbacks, 'afterBody', this, tooltipItems)
+ );
}
// Get the footer and beforeFooter and afterFooter lines
getFooter(tooltipItems, options) {
const {callbacks} = options;
- const beforeFooter = callbacks.beforeFooter.apply(this, [tooltipItems]);
- const footer = callbacks.footer.apply(this, [tooltipItems]);
- const afterFooter = callbacks.afterFooter.apply(this, [tooltipItems]);
+ const beforeFooter = invokeCallbackWithFallback(callbacks, 'beforeFooter', this, tooltipItems);
+ const footer = invokeCallbackWithFallback(callbacks, 'footer', this, tooltipItems);
+ const afterFooter = invokeCallbackWithFallback(callbacks, 'afterFooter', this, tooltipItems);
let lines = [];
lines = pushOrConcat(lines, splitNewlines(beforeFooter));
// Determine colors for boxes
each(tooltipItems, (context) => {
const scoped = overrideCallbacks(options.callbacks, context);
- labelColors.push(scoped.labelColor.call(this, context));
- labelPointStyles.push(scoped.labelPointStyle.call(this, context));
- labelTextColors.push(scoped.labelTextColor.call(this, context));
+ labelColors.push(invokeCallbackWithFallback(scoped, 'labelColor', this, context));
+ labelPointStyles.push(invokeCallbackWithFallback(scoped, 'labelPointStyle', this, context));
+ labelTextColors.push(invokeCallbackWithFallback(scoped, 'labelTextColor', this, context));
});
this.labelColors = labelColors;
duration: 200
}
},
- callbacks: {
- // Args are: (tooltipItems, data)
- beforeTitle: noop,
- title(tooltipItems) {
- if (tooltipItems.length > 0) {
- const item = tooltipItems[0];
- const labels = item.chart.data.labels;
- const labelCount = labels ? labels.length : 0;
-
- if (this && this.options && this.options.mode === 'dataset') {
- return item.dataset.label || '';
- } else if (item.label) {
- return item.label;
- } else if (labelCount > 0 && item.dataIndex < labelCount) {
- return labels[item.dataIndex];
- }
- }
-
- return '';
- },
- afterTitle: noop,
-
- // Args are: (tooltipItems, data)
- beforeBody: noop,
-
- // Args are: (tooltipItem, data)
- beforeLabel: noop,
- label(tooltipItem) {
- if (this && this.options && this.options.mode === 'dataset') {
- return tooltipItem.label + ': ' + tooltipItem.formattedValue || tooltipItem.formattedValue;
- }
-
- let label = tooltipItem.dataset.label || '';
-
- if (label) {
- label += ': ';
- }
- const value = tooltipItem.formattedValue;
- if (!isNullOrUndef(value)) {
- label += value;
- }
- return label;
- },
- labelColor(tooltipItem) {
- const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);
- const options = meta.controller.getStyle(tooltipItem.dataIndex);
- return {
- borderColor: options.borderColor,
- backgroundColor: options.backgroundColor,
- borderWidth: options.borderWidth,
- borderDash: options.borderDash,
- borderDashOffset: options.borderDashOffset,
- borderRadius: 0,
- };
- },
- labelTextColor() {
- return this.options.bodyColor;
- },
- labelPointStyle(tooltipItem) {
- const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);
- const options = meta.controller.getStyle(tooltipItem.dataIndex);
- return {
- pointStyle: options.pointStyle,
- rotation: options.rotation,
- };
- },
- afterLabel: noop,
-
- // Args are: (tooltipItems, data)
- afterBody: noop,
-
- // Args are: (tooltipItems, data)
- beforeFooter: noop,
- footer: noop,
- afterFooter: noop
- }
+ callbacks: defaultCallbacks
},
defaultRoutes: {
Model = TooltipModel<TType>,
Item = TooltipItem<TType>> {
- beforeTitle(this: Model, tooltipItems: Item[]): string | string[];
- title(this: Model, tooltipItems: Item[]): string | string[];
- afterTitle(this: Model, tooltipItems: Item[]): string | string[];
+ beforeTitle(this: Model, tooltipItems: Item[]): string | string[] | void;
+ title(this: Model, tooltipItems: Item[]): string | string[] | void;
+ afterTitle(this: Model, tooltipItems: Item[]): string | string[] | void;
- beforeBody(this: Model, tooltipItems: Item[]): string | string[];
- afterBody(this: Model, tooltipItems: Item[]): string | string[];
+ beforeBody(this: Model, tooltipItems: Item[]): string | string[] | void;
+ afterBody(this: Model, tooltipItems: Item[]): string | string[] | void;
- beforeLabel(this: Model, tooltipItem: Item): string | string[];
- label(this: Model, tooltipItem: Item): string | string[];
- afterLabel(this: Model, tooltipItem: Item): string | string[];
+ beforeLabel(this: Model, tooltipItem: Item): string | string[] | void;
+ label(this: Model, tooltipItem: Item): string | string[] | void;
+ afterLabel(this: Model, tooltipItem: Item): string | string[] | void;
- labelColor(this: Model, tooltipItem: Item): TooltipLabelStyle;
- labelTextColor(this: Model, tooltipItem: Item): Color;
- labelPointStyle(this: Model, tooltipItem: Item): { pointStyle: PointStyle; rotation: number };
+ labelColor(this: Model, tooltipItem: Item): TooltipLabelStyle | void;
+ labelTextColor(this: Model, tooltipItem: Item): Color | void;
+ labelPointStyle(this: Model, tooltipItem: Item): { pointStyle: PointStyle; rotation: number } | void;
- beforeFooter(this: Model, tooltipItems: Item[]): string | string[];
- footer(this: Model, tooltipItems: Item[]): string | string[];
- afterFooter(this: Model, tooltipItems: Item[]): string | string[];
+ beforeFooter(this: Model, tooltipItems: Item[]): string | string[] | void;
+ footer(this: Model, tooltipItems: Item[]): string | string[] | void;
+ afterFooter(this: Model, tooltipItems: Item[]): string | string[] | void;
}
export interface ExtendedPlugin<