| `font` | `Font` | Yes | `Chart.defaults.font` | See [Fonts](../general/fonts.md)
| `major` | `object` | | `{}` | [Major ticks configuration](./styling.mdx#major-tick-configuration).
| `padding` | `number` | | `0` | Sets the offset of the tick labels from the axis
-| `textStrokeColor` | `string` | | `` | The color of the stroke around the text.
-| `textStrokeWidth` | `number` | | `0` | Stroke width around the text.
+| `textStrokeColor` | [`Color`](../general/colors.md) | Yes | `` | The color of the stroke around the text.
+| `textStrokeWidth` | `number` | Yes | `0` | Stroke width around the text.
| `z` | `number` | | `0` | z-index of tick layer. Useful when ticks are drawn on chart area. Values <= 0 are drawn under datasets, > 0 on top.
import defaults from './core.defaults';
import Element from './core.element';
-import {_alignPixel, _measureText} from '../helpers/helpers.canvas';
+import {_alignPixel, _measureText, renderText} from '../helpers/helpers.canvas';
import {callback as call, each, finiteOrDefault, isArray, isFinite, isNullOrUndef, isObject, valueOrDefault} from '../helpers/helpers.core';
import {_factorize, toDegrees, toRadians, _int16Range, HALF_PI} from '../helpers/helpers.math';
import {toFont, resolve, toPadding} from '../helpers/helpers.options';
lineCount = isArray(label) ? label.length : 1;
const halfCount = lineCount / 2;
const color = resolve([optionTicks.color], me.getContext(i), i);
+ const strokeColor = resolve([optionTicks.textStrokeColor], me.getContext(i), i);
+ const strokeWidth = resolve([optionTicks.textStrokeWidth], me.getContext(i), i);
if (isHorizontal) {
x = pixel;
}
items.push({
- x,
- y,
rotation,
label,
font,
color,
+ strokeColor,
+ strokeWidth,
textOffset,
textAlign,
textBaseline,
+ translation: [x, y]
});
}
const ctx = me.ctx;
const items = me._labelItems || (me._labelItems = me._computeLabelItems(chartArea));
- let i, j, ilen, jlen;
+ let i, ilen;
for (i = 0, ilen = items.length; i < ilen; ++i) {
const item = items[i];
const tickFont = item.font;
- const useStroke = optionTicks.textStrokeWidth > 0 && optionTicks.textStrokeColor !== '';
-
- // Make sure we draw text in the correct color and font
- ctx.save();
- ctx.translate(item.x, item.y);
- ctx.rotate(item.rotation);
- ctx.font = tickFont.string;
- ctx.fillStyle = item.color;
- ctx.textAlign = item.textAlign;
- ctx.textBaseline = item.textBaseline;
-
- if (useStroke) {
- ctx.strokeStyle = optionTicks.textStrokeColor;
- ctx.lineWidth = optionTicks.textStrokeWidth;
- }
-
const label = item.label;
let y = item.textOffset;
- if (isArray(label)) {
- for (j = 0, jlen = label.length; j < jlen; ++j) {
- // We just make sure the multiline element is a string here..
- if (useStroke) {
- ctx.strokeText('' + label[j], 0, y);
- }
- ctx.fillText('' + label[j], 0, y);
- y += tickFont.lineHeight;
- }
- } else {
- if (useStroke) {
- ctx.strokeText(label, 0, y);
- }
- ctx.fillText(label, 0, y);
- }
- ctx.restore();
+ renderText(ctx, label, 0, y, tickFont, item);
}
}
rotation = isLeft ? -HALF_PI : HALF_PI;
}
- ctx.save();
- ctx.translate(scaleLabelX, scaleLabelY);
- ctx.rotate(rotation);
- ctx.textAlign = textAlign;
- ctx.textBaseline = 'middle';
- ctx.fillStyle = scaleLabel.color;
- ctx.font = scaleLabelFont.string;
- ctx.fillText(scaleLabel.labelString, 0, 0);
- ctx.restore();
+ renderText(ctx, scaleLabel.labelString, 0, 0, scaleLabelFont, {
+ color: scaleLabel.color,
+ rotation,
+ textAlign,
+ textBaseline: 'middle',
+ translation: [scaleLabelX, scaleLabelY],
+ });
}
draw(chartArea) {
target.x,
target.y);
}
+
+/**
+ * Render text onto the canvas
+ */
+export function renderText(ctx, text, x, y, font, opts = {}) {
+ const lines = isArray(text) ? text : [text];
+ const stroke = opts.strokeWidth > 0 && opts.strokeColor !== '';
+ let i, line;
+
+ ctx.save();
+
+ if (opts.translation) {
+ ctx.translate(opts.translation[0], opts.translation[1]);
+ }
+
+ if (!isNullOrUndef(opts.rotation)) {
+ ctx.rotate(opts.rotation);
+ }
+
+ ctx.font = font.fontString;
+
+ if (opts.color) {
+ ctx.fillStyle = opts.color;
+ }
+
+ if (opts.textAlign) {
+ ctx.textAlign = opts.textAlign;
+ }
+
+ if (opts.textBaseline) {
+ ctx.textBaseline = opts.textBaseline;
+ }
+
+ for (i = 0; i < lines.length; ++i) {
+ line = lines[i];
+
+ if (stroke) {
+ if (opts.strokeColor) {
+ ctx.strokeStyle = opts.strokeColor;
+ }
+
+ if (!isNullOrUndef(opts.strokeWidth)) {
+ ctx.lineWidth = opts.strokeWidth;
+ }
+
+ ctx.strokeText(line, x, y, opts.maxWidth);
+ }
+
+ ctx.fillText(line, x, y, opts.maxWidth);
+
+ if (opts.strikethrough || opts.underline) {
+ /**
+ * Now that IE11 support has been dropped, we can use more
+ * of the TextMetrics object. The actual bounding boxes
+ * are unflagged in Chrome, Firefox, Edge, and Safari so they
+ * can be safely used.
+ * See https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics#Browser_compatibility
+ */
+ const metrics = ctx.measureText(line);
+ const left = x - metrics.actualBoundingBoxLeft;
+ const right = x + metrics.actualBoundingBoxRight;
+ const top = y - metrics.actualBoundingBoxAscent;
+ const bottom = y + metrics.actualBoundingBoxDescent;
+ const yDecoration = opts.strikethrough ? (top + bottom) / 2 : bottom;
+
+ ctx.strokeStyle = ctx.fillStyle;
+ ctx.beginPath();
+ ctx.lineWidth = opts.decorationWidth || 2;
+ ctx.moveTo(left, yDecoration);
+ ctx.lineTo(right, yDecoration);
+ ctx.stroke();
+ }
+ y += font.lineHeight;
+ }
+
+ ctx.restore();
+}
import defaults from '../core/core.defaults';
import Element from '../core/core.element';
import layouts from '../core/core.layouts';
-import {drawPoint} from '../helpers/helpers.canvas';
+import {drawPoint, renderText} from '../helpers/helpers.canvas';
import {
callback as call, valueOrDefault, toFont, isObject,
toPadding, getRtlAdapter, overrideTextDirection, restoreTextDirection,
ctx.restore();
};
- const fillText = function(x, y, legendItem, textWidth) {
+ const fillText = function(x, y, legendItem) {
const halfFontSize = fontSize / 2;
const xLeft = rtlHelper.xPlus(x, boxWidth + halfFontSize);
- const yMiddle = y + (itemHeight / 2);
- ctx.fillText(legendItem.text, xLeft, yMiddle);
-
- if (legendItem.hidden) {
- // Strikethrough the text if hidden
- ctx.beginPath();
- ctx.lineWidth = 2;
- ctx.moveTo(xLeft, yMiddle);
- ctx.lineTo(rtlHelper.xPlus(xLeft, textWidth), yMiddle);
- ctx.stroke();
- }
+ renderText(ctx, legendItem.text, xLeft, y + (itemHeight / 2), labelFont, {strikethrough: legendItem.hidden});
};
// Horizontal
legendHitBoxes[i].top = y;
// Fill the actual label
- fillText(realX, y, legendItem, textWidth);
+ fillText(realX, y, legendItem);
if (isHorizontal) {
cursor.x += width + padding;
ctx.fillStyle = titleOpts.color;
ctx.font = titleFont.string;
- ctx.fillText(titleOpts.text, x, y);
+ renderText(ctx, titleOpts.text, x, y, titleFont);
}
/**
import layouts from '../core/core.layouts';
import {PI, isArray, toPadding, toFont} from '../helpers';
import {_toLeftRightCenter, _alignStartEnd} from '../helpers/helpers.extras';
+import {renderText} from '../helpers/helpers.canvas';
export class Title extends Element {
/**
const offset = lineHeight / 2 + me._padding.top;
const {titleX, titleY, maxWidth, rotation} = me._drawArgs(offset);
- ctx.save();
-
- ctx.fillStyle = opts.color;
- ctx.font = fontOpts.string;
-
- ctx.translate(titleX, titleY);
- ctx.rotate(rotation);
- ctx.textAlign = _toLeftRightCenter(opts.align);
- ctx.textBaseline = 'middle';
-
- const text = opts.text;
- if (isArray(text)) {
- let y = 0;
- for (let i = 0; i < text.length; ++i) {
- ctx.fillText(text[i], 0, y, maxWidth);
- y += lineHeight;
- }
- } else {
- ctx.fillText(text, 0, 0, maxWidth);
- }
-
- ctx.restore();
+ renderText(ctx, opts.text, 0, 0, fontOpts, {
+ color: opts.color,
+ maxWidth,
+ rotation,
+ textAlign: _toLeftRightCenter(opts.align),
+ textBaseline: 'middle',
+ translation: [titleX, titleY],
+ });
}
}
import defaults from '../core/core.defaults';
-import {_longestText} from '../helpers/helpers.canvas';
+import {_longestText, renderText} from '../helpers/helpers.canvas';
import {HALF_PI, isNumber, TAU, toDegrees, toRadians, _normalizeAngle} from '../helpers/helpers.math';
import LinearScaleBase from './scale.linearbase';
import Ticks from '../core/core.ticks';
return 'right';
}
-function fillText(ctx, text, position, lineHeight) {
- let y = position.y + lineHeight / 2;
- let i, ilen;
-
- if (isArray(text)) {
- for (i = 0, ilen = text.length; i < ilen; ++i) {
- ctx.fillText(text[i], position.x, y);
- y += lineHeight;
- }
- } else {
- ctx.fillText(text, position.x, y);
- }
-}
-
function adjustPointPositionForLabelHeight(angle, textSize, position) {
if (angle === 90 || angle === 270) {
position.y -= (textSize.h / 2);
const context = scale.getContext(i);
const plFont = toFont(resolve([pointLabelOpts.font], context, i), scale.chart.options.font);
- ctx.font = plFont.string;
- ctx.fillStyle = resolve([pointLabelOpts.color], context, i);
-
const angle = toDegrees(scale.getIndexAngle(i));
- ctx.textAlign = getTextAlignForAngle(angle);
adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition);
- fillText(ctx, scale.pointLabels[i], pointLabelPosition, plFont.lineHeight);
+ renderText(
+ ctx,
+ scale.pointLabels[i],
+ pointLabelPosition.x,
+ pointLabelPosition.y + (plFont.lineHeight / 2),
+ plFont,
+ {
+ color: resolve([pointLabelOpts.color], context, i),
+ textAlign: getTextAlignForAngle(angle),
+ }
+ );
}
ctx.restore();
}
const context = me.getContext(index);
const tickFont = me._resolveTickFontOptions(index);
- ctx.font = tickFont.string;
offset = me.getDistanceFromCenterForValue(me.ticks[index].value);
const showLabelBackdrop = resolve([tickOpts.showLabelBackdrop], context, index);
);
}
- ctx.fillStyle = tickOpts.color;
- ctx.fillText(tick.label, 0, -offset);
+ renderText(ctx, tick.label, 0, -offset, tickFont, {
+ color: tickOpts.color,
+ });
});
ctx.restore();
this._lineWidth = null;
this._strokeStyle = null;
this._textAlign = null;
+ this._textBaseline = null;
// Define properties here so that we can record each time they are set
Object.defineProperties(this, {
this._textAlign = align;
this.record('setTextAlign', [align]);
}
+ },
+ textBaseline: {
+ get: function() {
+ return this._textBaseline;
+ },
+ set: function(baseline) {
+ this._textBaseline = baseline;
+ this.record('setTextBaseline', [baseline]);
+ }
}
});
};
lineTo: function() {},
measureText: function(text) {
// return the number of characters * fixed size
- return text ? {width: text.length * 10} : {width: 0};
+ // Uses fake numbers for the bounding box
+ return text ? {
+ actualBoundingBoxAscent: 4,
+ actualBoundingBoxDescent: 8,
+ actualBoundingBoxLeft: 15,
+ actualBoundingBoxRight: 25,
+ width: text.length * 10
+ } : {
+ actualBoundingBoxAscent: 0,
+ actualBoundingBoxDescent: 0,
+ actualBoundingBoxLeft: 0,
+ actualBoundingBoxRight: 0,
+ width: 0
+ };
},
moveTo: function() {},
quadraticCurveTo: function() {},
args: ['foobar_1']
}]);
});
+
+ describe('renderText', function() {
+ it('should render multiple lines of text', function() {
+ var context = window.createMockContext();
+ var font = {fontString: '', lineHeight: 20};
+ helpers.renderText(context, ['foo', 'foo2'], 0, 0, font);
+
+ expect(context.getCalls()).toEqual([{
+ name: 'save',
+ args: [],
+ }, {
+ name: 'fillText',
+ args: ['foo', 0, 0, undefined],
+ }, {
+ name: 'fillText',
+ args: ['foo2', 0, 20, undefined],
+ }, {
+ name: 'restore',
+ args: [],
+ }]);
+ });
+
+ it('should accept the text maxWidth', function() {
+ var context = window.createMockContext();
+ var font = {fontString: '', lineHeight: 20};
+ helpers.renderText(context, 'foo', 0, 0, font, {maxWidth: 30});
+ expect(context.getCalls()).toEqual([{
+ name: 'save',
+ args: [],
+ }, {
+ name: 'fillText',
+ args: ['foo', 0, 0, 30],
+ }, {
+ name: 'restore',
+ args: [],
+ }]);
+ });
+
+ it('should underline the text', function() {
+ var context = window.createMockContext();
+ var font = {fontString: '', lineHeight: 20};
+ helpers.renderText(context, 'foo', 0, 0, font, {decorationWidth: 3, underline: true});
+
+ expect(context.getCalls()).toEqual([{
+ name: 'save',
+ args: [],
+ }, {
+ name: 'fillText',
+ args: ['foo', 0, 0, undefined],
+ }, {
+ name: 'measureText',
+ args: ['foo'],
+ }, {
+ name: 'setStrokeStyle',
+ args: [null],
+ }, {
+ name: 'beginPath',
+ args: [],
+ }, {
+ name: 'setLineWidth',
+ args: [3],
+ }, {
+ name: 'moveTo',
+ args: [-15, 8],
+ }, {
+ name: 'lineTo',
+ args: [25, 8],
+ }, {
+ name: 'stroke',
+ args: [],
+ }, {
+ name: 'restore',
+ args: [],
+ }]);
+ });
+
+ it('should strikethrough the text', function() {
+ var context = window.createMockContext();
+ var font = {fontString: '', lineHeight: 20};
+ helpers.renderText(context, 'foo', 0, 0, font, {strikethrough: true});
+
+ expect(context.getCalls()).toEqual([{
+ name: 'save',
+ args: [],
+ }, {
+ name: 'fillText',
+ args: ['foo', 0, 0, undefined],
+ }, {
+ name: 'measureText',
+ args: ['foo'],
+ }, {
+ name: 'setStrokeStyle',
+ args: [null],
+ }, {
+ name: 'beginPath',
+ args: [],
+ }, {
+ name: 'setLineWidth',
+ args: [2],
+ }, {
+ name: 'moveTo',
+ args: [-15, 2],
+ }, {
+ name: 'lineTo',
+ args: [25, 2],
+ }, {
+ name: 'stroke',
+ args: [],
+ }, {
+ name: 'restore',
+ args: [],
+ }]);
+ });
+
+ it('should set the fill style if supplied', function() {
+ var context = window.createMockContext();
+ var font = {fontString: '', lineHeight: 20};
+ helpers.renderText(context, 'foo', 0, 0, font, {color: 'red'});
+
+ expect(context.getCalls()).toEqual([{
+ name: 'save',
+ args: [],
+ }, {
+ name: 'setFillStyle',
+ args: ['red'],
+ }, {
+ name: 'fillText',
+ args: ['foo', 0, 0, undefined],
+ }, {
+ name: 'restore',
+ args: [],
+ }]);
+ });
+
+ it('should set the stroke style if supplied', function() {
+ var context = window.createMockContext();
+ var font = {fontString: '', lineHeight: 20};
+ helpers.renderText(context, 'foo', 0, 0, font, {strokeColor: 'red', strokeWidth: 2});
+ expect(context.getCalls()).toEqual([{
+ name: 'save',
+ args: [],
+ }, {
+ name: 'setStrokeStyle',
+ args: ['red'],
+ }, {
+ name: 'setLineWidth',
+ args: [2],
+ }, {
+ name: 'strokeText',
+ args: ['foo', 0, 0, undefined],
+ }, {
+ name: 'fillText',
+ args: ['foo', 0, 0, undefined],
+ }, {
+ name: 'restore',
+ args: [],
+ }]);
+ });
+
+ it('should set the text alignment', function() {
+ var context = window.createMockContext();
+ var font = {fontString: '', lineHeight: 20};
+ helpers.renderText(context, 'foo', 0, 0, font, {textAlign: 'left', textBaseline: 'middle'});
+
+ expect(context.getCalls()).toEqual([{
+ name: 'save',
+ args: [],
+ }, {
+ name: 'setTextAlign',
+ args: ['left'],
+ }, {
+ name: 'setTextBaseline',
+ args: ['middle'],
+ }, {
+ name: 'fillText',
+ args: ['foo', 0, 0, undefined],
+ }, {
+ name: 'restore',
+ args: [],
+ }]);
+ });
+
+ it('should translate and rotate text', function() {
+ var context = window.createMockContext();
+ var font = {fontString: '', lineHeight: 20};
+ helpers.renderText(context, 'foo', 0, 0, font, {rotation: 90, translation: [10, 20]});
+
+ expect(context.getCalls()).toEqual([{
+ name: 'save',
+ args: [],
+ }, {
+ name: 'translate',
+ args: [10, 20],
+ }, {
+ name: 'rotate',
+ args: [90],
+ }, {
+ name: 'fillText',
+ args: ['foo', 0, 0, undefined],
+ }, {
+ name: 'restore',
+ args: [],
+ }]);
+ });
+ });
});
expect(context.getCalls()).toEqual([{
name: 'save',
args: []
- }, {
- name: 'setFillStyle',
- args: ['#666']
}, {
name: 'translate',
args: [300, 67.2]
}, {
name: 'rotate',
args: [0]
+ }, {
+ name: 'setFillStyle',
+ args: ['#666']
}, {
name: 'setTextAlign',
args: ['center'],
+ }, {
+ name: 'setTextBaseline',
+ args: ['middle'],
}, {
name: 'fillText',
args: ['My title', 0, 0, 400]
expect(context.getCalls()).toEqual([{
name: 'save',
args: []
- }, {
- name: 'setFillStyle',
- args: ['#666']
}, {
name: 'translate',
args: [117.2, 250]
}, {
name: 'rotate',
args: [-0.5 * Math.PI]
+ }, {
+ name: 'setFillStyle',
+ args: ['#666']
}, {
name: 'setTextAlign',
args: ['center'],
+ }, {
+ name: 'setTextBaseline',
+ args: ['middle'],
}, {
name: 'fillText',
args: ['My title', 0, 0, 400]
expect(context.getCalls()).toEqual([{
name: 'save',
args: []
- }, {
- name: 'setFillStyle',
- args: ['#666']
}, {
name: 'translate',
args: [117.2, 250]
}, {
name: 'rotate',
args: [0.5 * Math.PI]
+ }, {
+ name: 'setFillStyle',
+ args: ['#666']
}, {
name: 'setTextAlign',
args: ['center'],
+ }, {
+ name: 'setTextBaseline',
+ args: ['middle'],
}, {
name: 'fillText',
args: ['My title', 0, 0, 400]
expect(mockContext.getCalls()).toEqual(Array.prototype.concat(drawBody, [
{name: 'setTextAlign', args: ['left']},
+ {name: 'setTextBaseline', args: ['middle']},
{name: 'setFillStyle', args: ['#fff']},
{name: 'fillText', args: ['title', 105, 111]},
{name: 'setTextAlign', args: ['left']},
+ {name: 'setTextBaseline', args: ['middle']},
{name: 'setFillStyle', args: ['#fff']},
{name: 'setFillStyle', args: ['#fff']},
{name: 'fillText', args: ['label', 105, 129]},
{name: 'setTextAlign', args: ['left']},
+ {name: 'setTextBaseline', args: ['middle']},
{name: 'setFillStyle', args: ['#fff']},
{name: 'fillText', args: ['footer', 105, 147]},
{name: 'restore', args: []}
expect(mockContext.getCalls()).toEqual(Array.prototype.concat(drawBody, [
{name: 'setTextAlign', args: ['right']},
+ {name: 'setTextBaseline', args: ['middle']},
{name: 'setFillStyle', args: ['#fff']},
{name: 'fillText', args: ['title', 195, 111]},
{name: 'setTextAlign', args: ['right']},
+ {name: 'setTextBaseline', args: ['middle']},
{name: 'setFillStyle', args: ['#fff']},
{name: 'setFillStyle', args: ['#fff']},
{name: 'fillText', args: ['label', 195, 129]},
{name: 'setTextAlign', args: ['right']},
+ {name: 'setTextBaseline', args: ['middle']},
{name: 'setFillStyle', args: ['#fff']},
{name: 'fillText', args: ['footer', 195, 147]},
{name: 'restore', args: []}
expect(mockContext.getCalls()).toEqual(Array.prototype.concat(drawBody, [
{name: 'setTextAlign', args: ['center']},
+ {name: 'setTextBaseline', args: ['middle']},
{name: 'setFillStyle', args: ['#fff']},
{name: 'fillText', args: ['title', 150, 111]},
{name: 'setTextAlign', args: ['center']},
+ {name: 'setTextBaseline', args: ['middle']},
{name: 'setFillStyle', args: ['#fff']},
{name: 'setFillStyle', args: ['#fff']},
{name: 'fillText', args: ['label', 150, 129]},
{name: 'setTextAlign', args: ['center']},
+ {name: 'setTextBaseline', args: ['middle']},
{name: 'setFillStyle', args: ['#fff']},
{name: 'fillText', args: ['footer', 150, 147]},
{name: 'restore', args: []}
expect(mockContext.getCalls()).toEqual(Array.prototype.concat(drawBody, [
{name: 'setTextAlign', args: ['right']},
+ {name: 'setTextBaseline', args: ['middle']},
{name: 'setFillStyle', args: ['#fff']},
{name: 'fillText', args: ['title', 195, 111]},
{name: 'setTextAlign', args: ['center']},
+ {name: 'setTextBaseline', args: ['middle']},
{name: 'setFillStyle', args: ['#fff']},
{name: 'setFillStyle', args: ['#fff']},
{name: 'fillText', args: ['label', 150, 129]},
{name: 'setTextAlign', args: ['left']},
+ {name: 'setTextBaseline', args: ['middle']},
{name: 'setFillStyle', args: ['#fff']},
{name: 'fillText', args: ['footer', 105, 147]},
{name: 'restore', args: []}
--- /dev/null
+export type Color = string | CanvasGradient | CanvasPattern;
import { PointStyle } from '../index.esm';
+import { Color } from '../color';
import { ChartArea } from '../geometric';
+import { CanvasFontSpec } from './helpers.options';
/**
* Clears the entire canvas associated to the given `chart`.
* @return The CSS font string. See https://developer.mozilla.org/en-US/docs/Web/CSS/font
*/
export function toFontString(font: { size: number; family: string; style?: string; weight?: string }): string | null;
+
+export interface RenderTextOpts {
+ /**
+ * The fill color of the text. If unset, the existing
+ * fillStyle property of the canvas is unchanged.
+ */
+ color?: Color;
+
+ /**
+ * The width of the strikethrough / underline
+ * @default 2
+ */
+ decorationWidth?: number;
+
+ /**
+ * The max width of the text in pixels
+ */
+ maxWidth?: number;
+
+ /**
+ * A rotation to be applied to the canvas
+ * This is applied after the translation is applied
+ */
+ rotation?: number;
+
+ /**
+ * Apply a strikethrough effect to the text
+ */
+ strikethrough?: boolean;
+
+ /**
+ * The color of the text stroke. If unset, the existing
+ * strokeStyle property of the context is unchanged
+ */
+ strokeColor?: Color;
+
+ /**
+ * The text stroke width. If unset, the existing
+ * lineWidth property of the context is unchanged
+ */
+ strokeWidth?: number;
+
+ /**
+ * The text alignment to use. If unset, the existing
+ * textAlign property of the context is unchanged
+ */
+ textAlign: CanvasTextAlign;
+
+ /**
+ * The text baseline to use. If unset, the existing
+ * textBaseline property of the context is unchanged
+ */
+ textBaseline: CanvasTextBaseline;
+
+ /**
+ * If specified, a translation to apply to the context
+ */
+ translation?: [number, number];
+
+ /**
+ * Underline the text
+ */
+ underline?: boolean;
+}
+
+export function renderText(
+ ctx: CanvasRenderingContext2D,
+ text: string | string[],
+ x: number,
+ y: number,
+ font: CanvasFontSpec,
+ opts?: RenderTextOpts
+): void;
import { TimeUnit } from "./adapters";
import { AnimationEvent } from './animation';
+import { Color } from './color';
import { Element }from './element';
import { ChartArea, Point } from './geometric';
import {
export { DateAdapterBase, DateAdapter, TimeUnit, _adapters } from './adapters';
export { Animation, Animations, Animator, AnimationEvent } from './animation';
+export { Color } from './color';
export { Element } from './element';
export { ChartArea, Point } from './geometric';
export {
unregister(item: ChartComponent): void;
}
-export type Color = string | CanvasGradient | CanvasPattern;
-
export interface ChartEvent {
type:
| 'contextmenu'
* The color of the stroke around the text.
* @default undefined
*/
- textStrokeColor: Color;
+ textStrokeColor: Scriptable<Color, ScriptableScaleContext>;
/**
* Stroke width around the text.
* @default 0
*/
- textStrokeWidth: number;
+ textStrokeWidth: Scriptable<number, ScriptableScaleContext>;
/**
* z-index of tick layer. Useful when ticks are drawn on chart area. Values <= 0 are drawn under datasets, > 0 on top.
* @default 0