diff --git a/src/core/core.scale.js b/src/core/core.scale.js index 50ddca8724c..8b8bf347292 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -11,7 +11,7 @@ const offsetFromEdge = (scale, edge, offset) => edge === 'top' || edge === 'left const getTicksLimit = (ticksLength, maxTicksLimit) => Math.min(maxTicksLimit || ticksLength, ticksLength); /** - * @typedef { import('./core.controller.js').default } Chart + * @typedef { import('../types/index.js').Chart } Chart * @typedef {{value:number | string, label?:string, major?:boolean, $context?:any}} Tick */ @@ -120,6 +120,7 @@ function createTickContext(parent, index, tick) { } function titleAlign(align, position, reverse) { + /** @type {CanvasTextAlign} */ let ret = _toLeftRightCenter(align); if ((reverse && position !== 'right') || (!reverse && position === 'right')) { ret = reverseAlign(ret); @@ -839,7 +840,7 @@ export default class Scale extends Element { } else if (isArray(label)) { // if it is an array let's measure each element for (j = 0, jlen = label.length; j < jlen; ++j) { - nestedLabel = label[j]; + nestedLabel = /** @type {string} */ (label[j]); // Undefined labels and arrays should not be measured if (!isNullOrUndef(nestedLabel) && !isArray(nestedLabel)) { width = _measureText(ctx, cache.data, cache.gc, width, nestedLabel); diff --git a/src/elements/element.line.js b/src/elements/element.line.js index 3305393dc0b..4384e4d7b84 100644 --- a/src/elements/element.line.js +++ b/src/elements/element.line.js @@ -22,6 +22,9 @@ function lineTo(ctx, previous, target) { ctx.lineTo(target.x, target.y); } +/** + * @returns {any} + */ function getLineMethod(options) { if (options.stepped) { return _steppedLineTo; diff --git a/src/helpers/helpers.canvas.js b/src/helpers/helpers.canvas.ts similarity index 54% rename from src/helpers/helpers.canvas.js rename to src/helpers/helpers.canvas.ts index 217c3f1edce..5221c438c26 100644 --- a/src/helpers/helpers.canvas.js +++ b/src/helpers/helpers.canvas.ts @@ -1,25 +1,28 @@ +import type { + Chart, + Point, + FontSpec, + CanvasFontSpec, + PointStyle, + RenderTextOpts, + BackdropOptions +} from '../types/index.js'; +import type { + TRBL, + SplinePoint, + RoundedRect, + TRBLCorners +} from '../types/geometric.js'; import {isArray, isNullOrUndef} from './helpers.core.js'; import {PI, TAU, HALF_PI, QUARTER_PI, TWO_THIRDS_PI, RAD_PER_DEG} from './helpers.math.js'; -/** - * Note: typedefs are auto-exported, so use a made-up `canvas` namespace where - * necessary to avoid duplicates with `export * from './helpers`; see - * https://github.com/microsoft/TypeScript/issues/46011 - * @typedef { import('../core/core.controller.js').default } canvas.Chart - * @typedef { import('../types/index.js').Point } Point - */ - -/** - * @namespace Chart.helpers.canvas - */ - /** * Converts the given font object into a CSS font string. - * @param {object} font - A font object. - * @return {string|null} The CSS font string. See https://developer.mozilla.org/en-US/docs/Web/CSS/font + * @param font - A font object. + * @return The CSS font string. See https://developer.mozilla.org/en-US/docs/Web/CSS/font * @private */ -export function toFontString(font) { +export function toFontString(font: FontSpec) { if (!font || isNullOrUndef(font.size) || isNullOrUndef(font.family)) { return null; } @@ -33,7 +36,13 @@ export function toFontString(font) { /** * @private */ -export function _measureText(ctx, data, gc, longest, string) { +export function _measureText( + ctx: CanvasRenderingContext2D, + data: Record, + gc: string[], + longest: number, + string: string +) { let textWidth = data[string]; if (!textWidth) { textWidth = data[string] = ctx.measureText(string).width; @@ -45,10 +54,19 @@ export function _measureText(ctx, data, gc, longest, string) { return longest; } +type Thing = string | undefined | null +type Things = (Thing | Thing[])[] + /** * @private */ -export function _longestText(ctx, font, arrayOfThings, cache) { +// eslint-disable-next-line complexity +export function _longestText( + ctx: CanvasRenderingContext2D, + font: string, + arrayOfThings: Things, + cache?: {data?: Record, garbageCollect?: string[], font?: string} +) { cache = cache || {}; let data = cache.data = cache.data || {}; let gc = cache.garbageCollect = cache.garbageCollect || []; @@ -64,12 +82,12 @@ export function _longestText(ctx, font, arrayOfThings, cache) { ctx.font = font; let longest = 0; const ilen = arrayOfThings.length; - let i, j, jlen, thing, nestedThing; + let i: number, j: number, jlen: number, thing: Thing | Thing[], nestedThing: Thing | Thing[]; for (i = 0; i < ilen; i++) { thing = arrayOfThings[i]; // Undefined strings and arrays should not be measured - if (thing !== undefined && thing !== null && isArray(thing) !== true) { + if (thing !== undefined && thing !== null && !isArray(thing)) { longest = _measureText(ctx, data, gc, longest, thing); } else if (isArray(thing)) { // if it is an array lets measure each element @@ -98,13 +116,13 @@ export function _longestText(ctx, font, arrayOfThings, cache) { /** * Returns the aligned pixel value to avoid anti-aliasing blur - * @param {canvas.Chart} chart - The chart instance. - * @param {number} pixel - A pixel value. - * @param {number} width - The width of the element. - * @returns {number} The aligned pixel value. + * @param chart - The chart instance. + * @param pixel - A pixel value. + * @param width - The width of the element. + * @returns The aligned pixel value. * @private */ -export function _alignPixel(chart, pixel, width) { +export function _alignPixel(chart: Chart, pixel: number, width: number) { const devicePixelRatio = chart.currentDevicePixelRatio; const halfWidth = width !== 0 ? Math.max(width / 2, 0.5) : 0; return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth; @@ -112,10 +130,8 @@ export function _alignPixel(chart, pixel, width) { /** * Clears the entire canvas. - * @param {HTMLCanvasElement} canvas - * @param {CanvasRenderingContext2D} [ctx] */ -export function clearCanvas(canvas, ctx) { +export function clearCanvas(canvas: HTMLCanvasElement, ctx?: CanvasRenderingContext2D) { ctx = ctx || canvas.getContext('2d'); ctx.save(); @@ -126,12 +142,32 @@ export function clearCanvas(canvas, ctx) { ctx.restore(); } -export function drawPoint(ctx, options, x, y) { +export interface DrawPointOptions { + pointStyle: PointStyle; + rotation?: number; + radius: number; + borderWidth: number; +} + +export function drawPoint( + ctx: CanvasRenderingContext2D, + options: DrawPointOptions, + x: number, + y: number +) { + // eslint-disable-next-line @typescript-eslint/no-use-before-define drawPointLegend(ctx, options, x, y, null); } -export function drawPointLegend(ctx, options, x, y, w) { - let type, xOffset, yOffset, size, cornerRadius, width, xOffsetW, yOffsetW; +// eslint-disable-next-line complexity +export function drawPointLegend( + ctx: CanvasRenderingContext2D, + options: DrawPointOptions, + x: number, + y: number, + w: number +) { + let type: string, xOffset: number, yOffset: number, size: number, cornerRadius: number, width: number, xOffsetW: number, yOffsetW: number; const style = options.pointStyle; const rotation = options.rotation; const radius = options.radius; @@ -157,24 +193,24 @@ export function drawPointLegend(ctx, options, x, y, w) { switch (style) { // Default includes circle - default: - if (w) { - ctx.ellipse(x, y, w / 2, radius, 0, 0, TAU); - } else { - ctx.arc(x, y, radius, 0, TAU); - } - ctx.closePath(); - break; - case 'triangle': - width = w ? w / 2 : radius; - ctx.moveTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius); - rad += TWO_THIRDS_PI; - ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius); - rad += TWO_THIRDS_PI; - ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius); - ctx.closePath(); - break; - case 'rectRounded': + default: + if (w) { + ctx.ellipse(x, y, w / 2, radius, 0, 0, TAU); + } else { + ctx.arc(x, y, radius, 0, TAU); + } + ctx.closePath(); + break; + case 'triangle': + width = w ? w / 2 : radius; + ctx.moveTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius); + rad += TWO_THIRDS_PI; + ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius); + rad += TWO_THIRDS_PI; + ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius); + ctx.closePath(); + break; + case 'rectRounded': // NOTE: the rounded rect implementation changed to use `arc` instead of // `quadraticCurveTo` since it generates better results when rect is // almost a circle. 0.516 (instead of 0.5) produces results with visually @@ -182,83 +218,83 @@ export function drawPointLegend(ctx, options, x, y, w) { // circle with `radius`. For more details, see the following PRs: // https://github.com/chartjs/Chart.js/issues/5597 // https://github.com/chartjs/Chart.js/issues/5858 - cornerRadius = radius * 0.516; - size = radius - cornerRadius; - xOffset = Math.cos(rad + QUARTER_PI) * size; - xOffsetW = Math.cos(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size); - yOffset = Math.sin(rad + QUARTER_PI) * size; - yOffsetW = Math.sin(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size); - ctx.arc(x - xOffsetW, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI); - ctx.arc(x + yOffsetW, y - xOffset, cornerRadius, rad - HALF_PI, rad); - ctx.arc(x + xOffsetW, y + yOffset, cornerRadius, rad, rad + HALF_PI); - ctx.arc(x - yOffsetW, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI); - ctx.closePath(); - break; - case 'rect': - if (!rotation) { - size = Math.SQRT1_2 * radius; - width = w ? w / 2 : size; - ctx.rect(x - width, y - size, 2 * width, 2 * size); + cornerRadius = radius * 0.516; + size = radius - cornerRadius; + xOffset = Math.cos(rad + QUARTER_PI) * size; + xOffsetW = Math.cos(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size); + yOffset = Math.sin(rad + QUARTER_PI) * size; + yOffsetW = Math.sin(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size); + ctx.arc(x - xOffsetW, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI); + ctx.arc(x + yOffsetW, y - xOffset, cornerRadius, rad - HALF_PI, rad); + ctx.arc(x + xOffsetW, y + yOffset, cornerRadius, rad, rad + HALF_PI); + ctx.arc(x - yOffsetW, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI); + ctx.closePath(); break; - } - rad += QUARTER_PI; + case 'rect': + if (!rotation) { + size = Math.SQRT1_2 * radius; + width = w ? w / 2 : size; + ctx.rect(x - width, y - size, 2 * width, 2 * size); + break; + } + rad += QUARTER_PI; /* falls through */ - case 'rectRot': - xOffsetW = Math.cos(rad) * (w ? w / 2 : radius); - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - yOffsetW = Math.sin(rad) * (w ? w / 2 : radius); - ctx.moveTo(x - xOffsetW, y - yOffset); - ctx.lineTo(x + yOffsetW, y - xOffset); - ctx.lineTo(x + xOffsetW, y + yOffset); - ctx.lineTo(x - yOffsetW, y + xOffset); - ctx.closePath(); - break; - case 'crossRot': - rad += QUARTER_PI; + case 'rectRot': + xOffsetW = Math.cos(rad) * (w ? w / 2 : radius); + xOffset = Math.cos(rad) * radius; + yOffset = Math.sin(rad) * radius; + yOffsetW = Math.sin(rad) * (w ? w / 2 : radius); + ctx.moveTo(x - xOffsetW, y - yOffset); + ctx.lineTo(x + yOffsetW, y - xOffset); + ctx.lineTo(x + xOffsetW, y + yOffset); + ctx.lineTo(x - yOffsetW, y + xOffset); + ctx.closePath(); + break; + case 'crossRot': + rad += QUARTER_PI; /* falls through */ - case 'cross': - xOffsetW = Math.cos(rad) * (w ? w / 2 : radius); - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - yOffsetW = Math.sin(rad) * (w ? w / 2 : radius); - ctx.moveTo(x - xOffsetW, y - yOffset); - ctx.lineTo(x + xOffsetW, y + yOffset); - ctx.moveTo(x + yOffsetW, y - xOffset); - ctx.lineTo(x - yOffsetW, y + xOffset); - break; - case 'star': - xOffsetW = Math.cos(rad) * (w ? w / 2 : radius); - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - yOffsetW = Math.sin(rad) * (w ? w / 2 : radius); - ctx.moveTo(x - xOffsetW, y - yOffset); - ctx.lineTo(x + xOffsetW, y + yOffset); - ctx.moveTo(x + yOffsetW, y - xOffset); - ctx.lineTo(x - yOffsetW, y + xOffset); - rad += QUARTER_PI; - xOffsetW = Math.cos(rad) * (w ? w / 2 : radius); - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - yOffsetW = Math.sin(rad) * (w ? w / 2 : radius); - ctx.moveTo(x - xOffsetW, y - yOffset); - ctx.lineTo(x + xOffsetW, y + yOffset); - ctx.moveTo(x + yOffsetW, y - xOffset); - ctx.lineTo(x - yOffsetW, y + xOffset); - break; - case 'line': - xOffset = w ? w / 2 : Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - break; - case 'dash': - ctx.moveTo(x, y); - ctx.lineTo(x + Math.cos(rad) * (w ? w / 2 : radius), y + Math.sin(rad) * radius); - break; - case false: - ctx.closePath(); - break; + case 'cross': + xOffsetW = Math.cos(rad) * (w ? w / 2 : radius); + xOffset = Math.cos(rad) * radius; + yOffset = Math.sin(rad) * radius; + yOffsetW = Math.sin(rad) * (w ? w / 2 : radius); + ctx.moveTo(x - xOffsetW, y - yOffset); + ctx.lineTo(x + xOffsetW, y + yOffset); + ctx.moveTo(x + yOffsetW, y - xOffset); + ctx.lineTo(x - yOffsetW, y + xOffset); + break; + case 'star': + xOffsetW = Math.cos(rad) * (w ? w / 2 : radius); + xOffset = Math.cos(rad) * radius; + yOffset = Math.sin(rad) * radius; + yOffsetW = Math.sin(rad) * (w ? w / 2 : radius); + ctx.moveTo(x - xOffsetW, y - yOffset); + ctx.lineTo(x + xOffsetW, y + yOffset); + ctx.moveTo(x + yOffsetW, y - xOffset); + ctx.lineTo(x - yOffsetW, y + xOffset); + rad += QUARTER_PI; + xOffsetW = Math.cos(rad) * (w ? w / 2 : radius); + xOffset = Math.cos(rad) * radius; + yOffset = Math.sin(rad) * radius; + yOffsetW = Math.sin(rad) * (w ? w / 2 : radius); + ctx.moveTo(x - xOffsetW, y - yOffset); + ctx.lineTo(x + xOffsetW, y + yOffset); + ctx.moveTo(x + yOffsetW, y - xOffset); + ctx.lineTo(x - yOffsetW, y + xOffset); + break; + case 'line': + xOffset = w ? w / 2 : Math.cos(rad) * radius; + yOffset = Math.sin(rad) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + xOffset, y + yOffset); + break; + case 'dash': + ctx.moveTo(x, y); + ctx.lineTo(x + Math.cos(rad) * (w ? w / 2 : radius), y + Math.sin(rad) * radius); + break; + case false: + ctx.closePath(); + break; } ctx.fill(); @@ -269,34 +305,43 @@ export function drawPointLegend(ctx, options, x, y, w) { /** * Returns true if the point is inside the rectangle - * @param {Point} point - The point to test - * @param {object} area - The rectangle - * @param {number} [margin] - allowed margin - * @returns {boolean} + * @param point - The point to test + * @param area - The rectangle + * @param margin - allowed margin * @private */ -export function _isPointInArea(point, area, margin) { +export function _isPointInArea( + point: Point, + area: TRBL, + margin?: number +) { margin = margin || 0.5; // margin - default is to match rounded decimals return !area || (point && point.x > area.left - margin && point.x < area.right + margin && point.y > area.top - margin && point.y < area.bottom + margin); } -export function clipArea(ctx, area) { +export function clipArea(ctx: CanvasRenderingContext2D, area: TRBL) { ctx.save(); ctx.beginPath(); ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top); ctx.clip(); } -export function unclipArea(ctx) { +export function unclipArea(ctx: CanvasRenderingContext2D) { ctx.restore(); } /** * @private */ -export function _steppedLineTo(ctx, previous, target, flip, mode) { +export function _steppedLineTo( + ctx: CanvasRenderingContext2D, + previous: Point, + target: Point, + flip?: boolean, + mode?: string +) { if (!previous) { return ctx.lineTo(target.x, target.y); } @@ -315,7 +360,12 @@ export function _steppedLineTo(ctx, previous, target, flip, mode) { /** * @private */ -export function _bezierCurveTo(ctx, previous, target, flip) { +export function _bezierCurveTo( + ctx: CanvasRenderingContext2D, + previous: SplinePoint, + target: SplinePoint, + flip?: boolean +) { if (!previous) { return ctx.lineTo(target.x, target.y); } @@ -328,47 +378,7 @@ export function _bezierCurveTo(ctx, previous, target, flip) { 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(); - ctx.font = font.string; - setRenderOpts(ctx, opts); - - for (i = 0; i < lines.length; ++i) { - line = lines[i]; - - if (opts.backdrop) { - drawBackdrop(ctx, opts.backdrop); - } - - 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); - decorateText(ctx, x, y, line, opts); - - y += font.lineHeight; - } - - ctx.restore(); -} - -function setRenderOpts(ctx, opts) { +function setRenderOpts(ctx: CanvasRenderingContext2D, opts: RenderTextOpts) { if (opts.translation) { ctx.translate(opts.translation[0], opts.translation[1]); } @@ -390,7 +400,13 @@ function setRenderOpts(ctx, opts) { } } -function decorateText(ctx, x, y, line, opts) { +function decorateText( + ctx: CanvasRenderingContext2D, + x: number, + y: number, + line: string, + opts: RenderTextOpts +) { if (opts.strikethrough || opts.underline) { /** * Now that IE11 support has been dropped, we can use more @@ -415,20 +431,70 @@ function decorateText(ctx, x, y, line, opts) { } } -function drawBackdrop(ctx, opts) { +function drawBackdrop(ctx: CanvasRenderingContext2D, opts: BackdropOptions) { const oldColor = ctx.fillStyle; - ctx.fillStyle = opts.color; + ctx.fillStyle = opts.color as string; ctx.fillRect(opts.left, opts.top, opts.width, opts.height); ctx.fillStyle = oldColor; } +/** + * Render text onto the canvas + */ +export function renderText( + ctx: CanvasRenderingContext2D, + text: string | string[], + x: number, + y: number, + font: CanvasFontSpec, + opts: RenderTextOpts = {} +) { + const lines = isArray(text) ? text : [text]; + const stroke = opts.strokeWidth > 0 && opts.strokeColor !== ''; + let i: number, line: string; + + ctx.save(); + ctx.font = font.string; + setRenderOpts(ctx, opts); + + for (i = 0; i < lines.length; ++i) { + line = lines[i]; + + if (opts.backdrop) { + drawBackdrop(ctx, opts.backdrop); + } + + 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); + decorateText(ctx, x, y, line, opts); + + y += Number(font.lineHeight); + } + + ctx.restore(); +} + /** * Add a path of a rectangle with rounded corners to the current sub-path - * @param {CanvasRenderingContext2D} ctx Context - * @param {*} rect Bounding rect + * @param ctx - Context + * @param rect - Bounding rect */ -export function addRoundedRectPath(ctx, rect) { +export function addRoundedRectPath( + ctx: CanvasRenderingContext2D, + rect: RoundedRect & { radius: TRBLCorners } +) { const {x, y, w, h, radius} = rect; // top left arc diff --git a/src/helpers/helpers.curve.ts b/src/helpers/helpers.curve.ts index 97b76993e64..7dd0b7c3465 100644 --- a/src/helpers/helpers.curve.ts +++ b/src/helpers/helpers.curve.ts @@ -1,19 +1,7 @@ import {almostEquals, distanceBetweenPoints, sign} from './helpers.math.js'; import {_isPointInArea} from './helpers.canvas.js'; import type {ChartArea} from '../types/index.js'; - -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; -} +import type {SplinePoint} from '../types/geometric.js'; const EPSILON = Number.EPSILON || 1e-14; diff --git a/src/helpers/helpers.interpolation.ts b/src/helpers/helpers.interpolation.ts index 202575629d1..d3427b5592d 100644 --- a/src/helpers/helpers.interpolation.ts +++ b/src/helpers/helpers.interpolation.ts @@ -1,5 +1,4 @@ -import type {Point} from '../types/geometric.js'; -import type {SplinePoint} from './helpers.curve.js'; +import type {Point, SplinePoint} from '../types/geometric.js'; /** * @private diff --git a/src/helpers/helpers.options.ts b/src/helpers/helpers.options.ts index c476ccb5e1a..a69d52f0632 100644 --- a/src/helpers/helpers.options.ts +++ b/src/helpers/helpers.options.ts @@ -1,7 +1,7 @@ import defaults from '../core/core.defaults.js'; import {isArray, isObject, toDimension, valueOrDefault} from './helpers.core.js'; -import {Point, toFontString} from './helpers.canvas.js'; -import type {ChartArea, FontSpec} from '../types/index.js'; +import {toFontString} from './helpers.canvas.js'; +import type {ChartArea, FontSpec, Point} from '../types/index.js'; import type {TRBL, TRBLCorners} from '../types/geometric.js'; const LINE_HEIGHT = /^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/; @@ -104,10 +104,6 @@ export function toPadding(value?: number | TRBL): ChartArea { return obj; } -export interface CanvasFontSpec extends FontSpec { - string: string; -} - /** * Parses font options and returns the font object. * @param options - A object that contains font options to be parsed. diff --git a/src/helpers/types.ts b/src/helpers/types.ts deleted file mode 100644 index 3c3badbc892..00000000000 --- a/src/helpers/types.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Temporary entry point of the types at the time of the transition. - * After transition done need to remove it in favor of index.ts - */ - -// export * from '..js'; -export * from './helpers.color.js'; -export * from './helpers.collection.js'; -export * from './helpers.core.js'; -export * from './helpers.curve.js'; -export * from './helpers.dom.js'; -export * from './helpers.easing.js'; -export * from './helpers.extras.js'; -export * from './helpers.interpolation.js'; -export * from './helpers.intl.js'; -export * from './helpers.math.js'; -export * from './helpers.options.js'; -export * from './helpers.rtl.js'; -export * from '../types/helpers/index.js'; diff --git a/src/types/geometric.d.ts b/src/types/geometric.d.ts index e8e4f27b285..9df01f16487 100644 --- a/src/types/geometric.d.ts +++ b/src/types/geometric.d.ts @@ -37,3 +37,16 @@ export type RoundedRect = { } export type Padding = Partial | number | Point; + +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; +} diff --git a/src/types/helpers/helpers.canvas.d.ts b/src/types/helpers/helpers.canvas.d.ts deleted file mode 100644 index 41f99b2ad10..00000000000 --- a/src/types/helpers/helpers.canvas.d.ts +++ /dev/null @@ -1,135 +0,0 @@ -import {PointStyle, Scriptable, ScriptableScaleContext} from '../index.js'; -import {Color} from '../color.js'; -import {ChartArea, RoundedRect} from '../geometric.js'; -import {CanvasFontSpec} from '../../helpers/helpers.options.js'; - -export function clearCanvas(canvas: HTMLCanvasElement, ctx?: CanvasRenderingContext2D): void; - -export function clipArea(ctx: CanvasRenderingContext2D, area: ChartArea): void; - -export function unclipArea(ctx: CanvasRenderingContext2D): void; - -export interface DrawPointOptions { - pointStyle: PointStyle; - rotation?: number; - radius: number; - borderWidth: number; -} - -export function drawPoint(ctx: CanvasRenderingContext2D, options: DrawPointOptions, x: number, y: number): void; - -export function drawPointLegend(ctx: CanvasRenderingContext2D, options: DrawPointOptions, x: number, y: number, w: number): void; - -/** - * Converts the given font object into a CSS font string. - * @param font a font object - * @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; - - /** - * Dimensions for drawing the label backdrop - */ - backdrop?: BackdropOptions; -} - -export interface BackdropOptions { - /** - * Left position of backdrop as pixel - */ - left: number; - - /** - * Top position of backdrop as pixel - */ - top: number; - - /** - * Width of backdrop in pixels - */ - width: number; - - /** - * Height of backdrop in pixels - */ - height: number; - - /** - * Color of label backdrops. - */ - color: Scriptable; -} - -export function renderText( - ctx: CanvasRenderingContext2D, - text: string | string[], - x: number, - y: number, - font: CanvasFontSpec, - opts?: RenderTextOpts -): void; - -export function addRoundedRectPath(ctx: CanvasRenderingContext2D, rect: RoundedRect): void; diff --git a/src/types/helpers/helpers.segment.d.ts b/src/types/helpers/helpers.segment.d.ts deleted file mode 100644 index cb0ff5c3b54..00000000000 --- a/src/types/helpers/helpers.segment.d.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/src/types/helpers/index.d.ts b/src/types/helpers/index.d.ts deleted file mode 100644 index 9aa9cf2bdf3..00000000000 --- a/src/types/helpers/index.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './helpers.canvas.js'; -export * from './helpers.canvas.js'; -export * from './helpers.segment.js'; diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 6caf2174d45..c4f042ec16e 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -10,9 +10,7 @@ import {Color} from './color.js'; import Element from '../core/core.element.js'; import {ChartArea, Padding, Point} from './geometric.js'; import {LayoutItem, LayoutPosition} from './layout.js'; -import {RenderTextOpts} from './helpers/helpers.canvas.js'; -import {CanvasFontSpec} from '../helpers/helpers.options.js'; -import type {ColorsPluginOptions} from '../plugins/plugin.colors.js'; +import {ColorsPluginOptions} from '../plugins/plugin.colors.js'; export {EasingFunction} from '../helpers/helpers.easing.js'; export {default as ArcElement, ArcProps} from '../elements/element.arc.js'; @@ -548,6 +546,8 @@ export declare class Chart< isPluginEnabled(pluginId: string): boolean; + getContext(): { chart: Chart, type: string }; + static readonly defaults: Defaults; static readonly overrides: Overrides; static readonly version: string; @@ -1359,6 +1359,102 @@ export interface ScriptableScalePointLabelContext { type: string; } +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; + + /** + * Dimensions for drawing the label backdrop + */ + backdrop?: BackdropOptions; +} + +export interface BackdropOptions { + /** + * Left position of backdrop as pixel + */ + left: number; + + /** + * Top position of backdrop as pixel + */ + top: number; + + /** + * Width of backdrop in pixels + */ + width: number; + + /** + * Height of backdrop in pixels + */ + height: number; + + /** + * Color of label backdrops. + */ + color: Scriptable; +} + export interface LabelItem { label: string | string[]; font: CanvasFontSpec; @@ -1658,6 +1754,10 @@ export interface FontSpec { lineHeight: number | string; } +export interface CanvasFontSpec extends FontSpec { + string: string; +} + export type TextAlign = 'left' | 'center' | 'right'; export type Align = 'start' | 'center' | 'end'; @@ -3655,6 +3755,8 @@ export interface ChartData< TLabel = unknown > { labels?: TLabel[]; + xLabels?: TLabel[]; + yLabels?: TLabel[]; datasets: ChartDataset[]; } @@ -3664,6 +3766,8 @@ export interface ChartDataCustomTypesPerDataset< TLabel = unknown > { labels?: TLabel[]; + xLabels?: TLabel[]; + yLabels?: TLabel[]; datasets: ChartDatasetCustomTypesPerDataset[]; }