UNPKG

@devexperts/dxcharts-lite

Version:
184 lines (183 loc) 10.6 kB
/* * Copyright (C) 2019 - 2026 Devexperts Solutions IE Limited * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. * If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. */ /* * Copyright (C) 2019 - 2024 Devexperts Solutions IE Limited * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. * If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { getFontFromConfig, } from '../../chart.config'; import { drawPriceLabel, drawRoundedRect } from '../../utils/canvas/canvas-drawing-functions.utils'; import { calculateSymbolHeight, calculateTextWidth } from '../../utils/canvas/canvas-font-measure-tool.utils'; import { getLabelTextColorByBackgroundColor } from '../../utils/canvas/canvas-text-functions.utils'; import { round } from '../../utils/math.utils'; export const DEFAULT_PRICE_LABEL_PADDING = 4; /** * Draws badge label on Y axis with provided parameters. * @param ctx - canvas 2D context to draw on * @param bounds - bounds of Y axis * @param text - text to draw * @param centralY - y * @param config - label styles config * @param yAxisState * @param yAxisColors * @param checkBoundaries */ export function drawBadgeLabel(ctx, bounds, text, centralY, config, yAxisState, yAxisColors, checkBoundaries = true) { var _a, _b, _c, _d, _e, _f, _g; const align = yAxisState.align; const textFont = (_a = config.textFont) !== null && _a !== void 0 ? _a : getFontFromConfig(yAxisState); const bgColor = config.bgColor; const textColor = (_b = config.textColor) !== null && _b !== void 0 ? _b : getLabelTextColorByBackgroundColor(bgColor, yAxisColors.labelTextColor, yAxisColors.labelInvertedTextColor); const paddingTop = (_c = config.paddingTop) !== null && _c !== void 0 ? _c : DEFAULT_PRICE_LABEL_PADDING; const paddingBottom = (_d = config.paddingBottom) !== null && _d !== void 0 ? _d : DEFAULT_PRICE_LABEL_PADDING; const paddingEnd = (_e = config.paddingEnd) !== null && _e !== void 0 ? _e : DEFAULT_PRICE_LABEL_PADDING; const halfFontHeight = round(calculateSymbolHeight(textFont, ctx) / 2); const labelBoxTopY = centralY - halfFontHeight - paddingTop; const labelBoxBottomY = centralY + halfFontHeight + paddingBottom; const labelBoxHeight = labelBoxBottomY - labelBoxTopY; // do not draw, if label is out of bounds if (checkBoundaries && !checkLabelInBoundaries(centralY, bounds, labelBoxHeight)) { return; } ctx.save(); ctx.fillStyle = bgColor; ctx.strokeStyle = bgColor; const labelForeWidth = round(bounds.width / 6); const x1 = align === 'right' ? bounds.x : bounds.x + bounds.width; const x2 = align === 'right' ? x1 + labelForeWidth : x1 - labelForeWidth; const xTextOffset = yAxisState.labelBoxMargin.end; const marginEnd = xTextOffset - paddingEnd; // main body label width, without triangle const width = bounds.width - labelForeWidth - marginEnd; drawPriceLabel(ctx, x2, labelBoxTopY, x1, labelBoxTopY + round(labelBoxHeight / 2), x2, labelBoxTopY + labelBoxHeight, width, (_g = (_f = yAxisState.typeConfig.badge) === null || _f === void 0 ? void 0 : _f.rounded) !== null && _g !== void 0 ? _g : false, align); ctx.fillStyle = textColor; ctx.font = textFont; const textX = align === 'right' ? bounds.x + bounds.width - calculateTextWidth(text, ctx, textFont) - xTextOffset : bounds.x + xTextOffset; ctx.fillText(text, textX, centralY + halfFontHeight - 1); // -1 for font height adjustment ctx.restore(); } /** * Draws rectangle label on Y axis with provided parameters. * @param ctx - canvas 2D context to draw on * @param bounds - bounds of Y axis * @param text - text to draw * @param centralY - y * @param config - label styles config * @param yAxisState * @param yAxisColors * @param checkBoundaries */ export function drawRectLabel(ctx, bounds, text, centralY, config, yAxisState, yAxisColors, checkBoundaries = true) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l; const align = yAxisState.align; const textFont = (_a = config.textFont) !== null && _a !== void 0 ? _a : getFontFromConfig(yAxisState); const bgColor = config.bgColor; const textColor = (_b = config.textColor) !== null && _b !== void 0 ? _b : getLabelTextColorByBackgroundColor(bgColor, yAxisColors.labelTextColor, yAxisColors.labelInvertedTextColor); const paddings = (_c = yAxisState.typeConfig.rectangle) === null || _c === void 0 ? void 0 : _c.paddings; const paddingTop = (_e = (_d = config.paddingTop) !== null && _d !== void 0 ? _d : paddings === null || paddings === void 0 ? void 0 : paddings.top) !== null && _e !== void 0 ? _e : DEFAULT_PRICE_LABEL_PADDING; const paddingBottom = (_g = (_f = config.paddingBottom) !== null && _f !== void 0 ? _f : paddings === null || paddings === void 0 ? void 0 : paddings.bottom) !== null && _g !== void 0 ? _g : DEFAULT_PRICE_LABEL_PADDING; const paddingEnd = (_j = (_h = config.paddingEnd) !== null && _h !== void 0 ? _h : paddings === null || paddings === void 0 ? void 0 : paddings.end) !== null && _j !== void 0 ? _j : DEFAULT_PRICE_LABEL_PADDING; const paddingStart = config.paddingStart; const fontHeight = calculateSymbolHeight(textFont, ctx); const labelBoxTopY = centralY - fontHeight / 2 - paddingTop; const labelBoxBottomY = centralY + fontHeight / 2 + paddingBottom; const labelBoxHeight = labelBoxBottomY - labelBoxTopY; const rounded = (_k = config.rounded) !== null && _k !== void 0 ? _k : (_l = yAxisState.typeConfig.rectangle) === null || _l === void 0 ? void 0 : _l.rounded; // do not draw, if label is out of bounds if (checkBoundaries && !checkLabelInBoundaries(centralY, bounds, labelBoxHeight)) { return; } ctx.save(); ctx.fillStyle = bgColor; ctx.strokeStyle = bgColor; const xTextOffset = yAxisState.labelBoxMargin.end; ctx.font = textFont; const textWidth = calculateTextWidth(text, ctx, textFont); const marginEnd = xTextOffset - paddingEnd; const width = paddingStart !== undefined ? textWidth + paddingStart + paddingEnd : bounds.width - marginEnd; const x = align === 'right' ? bounds.x + bounds.width - marginEnd - width : bounds.x + marginEnd; const textX = align === 'right' ? bounds.x + bounds.width - textWidth - xTextOffset : xTextOffset; if (rounded) { drawRoundedRect(ctx, x, labelBoxTopY, width, labelBoxHeight, 4, true); } else { ctx.fillRect(x, labelBoxTopY, width, labelBoxHeight); } ctx.fillStyle = textColor; ctx.fillText(text, textX, centralY + fontHeight / 2 - 1); // -1 for font height adjustment ctx.restore(); } /** * Draws rectangle label on Y axis with provided parameters but with transparent background. * @param ctx - canvas 2D context to draw on * @param bounds - bounds of Y axis * @param text - text to draw * @param centralY - y * @param config - label styles config * @param yAxisState * @param yAxisColors * @param checkBoundaries */ export function drawPlainLabel(ctx, bounds, text, centralY, config, yAxisState, yAxisColors, checkBoundaries = true) { var _a, _b, _c, _d, _e, _f, _g, _h, _j; const align = yAxisState.align; const textFont = (_a = config.textFont) !== null && _a !== void 0 ? _a : getFontFromConfig(yAxisState); const bgColor = yAxisColors.backgroundColor; const textColor = (_b = config.textColor) !== null && _b !== void 0 ? _b : getLabelTextColorByBackgroundColor(bgColor, yAxisColors.labelTextColor, yAxisColors.labelInvertedTextColor); const paddings = (_c = yAxisState.typeConfig.rectangle) === null || _c === void 0 ? void 0 : _c.paddings; const paddingTop = (_e = (_d = config.paddingTop) !== null && _d !== void 0 ? _d : paddings === null || paddings === void 0 ? void 0 : paddings.top) !== null && _e !== void 0 ? _e : DEFAULT_PRICE_LABEL_PADDING; const paddingBottom = (_g = (_f = config.paddingBottom) !== null && _f !== void 0 ? _f : paddings === null || paddings === void 0 ? void 0 : paddings.bottom) !== null && _g !== void 0 ? _g : DEFAULT_PRICE_LABEL_PADDING; const paddingEnd = (_j = (_h = config.paddingEnd) !== null && _h !== void 0 ? _h : paddings === null || paddings === void 0 ? void 0 : paddings.end) !== null && _j !== void 0 ? _j : DEFAULT_PRICE_LABEL_PADDING; const paddingStart = config.paddingStart; const fontHeight = calculateSymbolHeight(textFont, ctx); const labelBoxTopY = centralY - fontHeight / 2 - paddingTop; const labelBoxBottomY = centralY + fontHeight / 2 + paddingBottom; const labelBoxHeight = labelBoxBottomY - labelBoxTopY; // do not draw, if label is out of bounds if (checkBoundaries && !checkLabelInBoundaries(centralY, bounds, labelBoxHeight)) { return; } ctx.save(); ctx.fillStyle = bgColor; ctx.strokeStyle = bgColor; const xTextOffset = yAxisState.labelBoxMargin.end; ctx.font = textFont; const textWidth = calculateTextWidth(text, ctx, textFont); const marginEnd = xTextOffset - paddingEnd; const width = paddingStart !== undefined ? textWidth + paddingStart + paddingEnd : bounds.width - marginEnd; const x = align === 'right' ? bounds.x + bounds.width - marginEnd - width : bounds.x + marginEnd; const textX = align === 'right' ? bounds.x + bounds.width - textWidth - xTextOffset : xTextOffset; // label can overlap with regular price y-axis label, so we need to hide regular y-axis label ctx.fillStyle = bgColor; ctx.strokeStyle = bgColor; ctx.fillRect(x, labelBoxTopY, width, labelBoxHeight); ctx.fillStyle = textColor; ctx.fillText(text, textX, centralY + fontHeight / 2 - 1); // -1 for font height adjustment ctx.restore(); } /** * Offset from the center of label to the top/bottom. * * @param font Label font * @param ctx Drawing context * @param paddingTop - extra padding from top */ export function getLabelYOffset(font, ctx, paddingTop = DEFAULT_PRICE_LABEL_PADDING) { const fontHeight = calculateSymbolHeight(font, ctx); return fontHeight / 2 + paddingTop; } /** * Checks if label fits in chart scale boundaries * @param centralY * @param bounds * @param labelBoxHeight * returns true if label fits */ export function checkLabelInBoundaries(centralY, bounds, labelBoxHeight) { return !(centralY < bounds.y + labelBoxHeight / 2 || centralY > bounds.y + bounds.height - labelBoxHeight / 2); }