@devexperts/dxcharts-lite
Version:
167 lines (165 loc) • 6.75 kB
JavaScript
/*
* Copyright (C) 2019 - 2025 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 Color from 'color';
/**
* Baseline Height in Project
*/
const BASELINE = 1.33;
/**
* Sets the font, fill style and text alignment of a canvas context based on the provided properties.
* @param {CanvasRenderingContext2D} ctx - The canvas context to modify.
* @param {CanvasTextProperties} properties - An object containing the properties to apply to the canvas context.
* @param {string} properties.textStyle - The style of the text. Can be 'italic', 'bold' or both.
* @param {number} properties.textSize - The size of the text in pixels.
* @param {string} properties.textFontFamily - The font family of the text.
* @param {string} properties.textFill - The fill style of the text.
* @param {boolean} properties.rtl - Whether the text should be aligned to the right or to the left.
*/
export function prepareTextForFill(ctx, properties) {
let textStyles = '';
if (properties.textStyle) {
properties.textStyle.italic && (textStyles += `italic `);
properties.textStyle.bold && (textStyles += `bold `);
}
ctx.font = textStyles + (properties.textSize || 12) + ' ' + (properties.textFontFamily || 'monospace');
ctx.fillStyle = properties.textFill || '#FFFFFF';
if (properties.rtl) {
ctx.textAlign = 'right';
}
else {
ctx.textAlign = 'start';
}
}
/**
* Calculates the line height of a text based on the font size of the provided CanvasRenderingContext2D.
* @param {CanvasRenderingContext2D} ctx - The CanvasRenderingContext2D object used to draw the text.
* @param includeBaseLine
* @returns {number} The calculated line height of the text.
*/
export function getTextLineHeight(ctx, includeBaseLine = true) {
const textSizeMatch = ctx.font.match(/(\d+.)?\d+(px|pt)/gi);
let textSize = '10px';
if (textSizeMatch && textSizeMatch.length) {
if (textSizeMatch[0].includes('pt')) {
const ptSize = +textSizeMatch[0].slice(0, textSizeMatch[0].indexOf('pt'));
textSize = (ptSize * 96) / 72 + 'px';
}
else {
textSize = textSizeMatch[0];
}
}
return includeBaseLine ? parseInt(textSize, 10) * BASELINE : parseInt(textSize, 10);
}
/**
* Calculates text bounds [textWidth, textHeight, lineHeight]
* @param ctx
* @param lines
* @param properties
*/
export function getTextBounds(ctx, lines, properties) {
ctx.save();
prepareTextForFill(ctx, properties);
const textWidth = Math.ceil(Math.max.apply(Math, lines.map((text) => {
return ctx.measureText(text).width;
})));
const lineHeight = getTextLineHeight(ctx);
const textHeight = lineHeight * lines.length;
ctx.restore();
return [textWidth, textHeight, lineHeight];
}
/**
* Splits multiline text to array of lines
* @param text
*/
export function getTextLines(text) {
return (text || '').split(/\r\n|\r|\n/);
}
/**
* Draws multiple lines of text on a canvas context at a given position.
* @param {CanvasRenderingContext2D} ctx - The canvas context to draw on.
* @param {string[]} lines - An array of strings representing the lines of text to draw.
* @param {number} x - The x-coordinate of the starting position of the text.
* @param {number} y - The y-coordinate of the starting position of the text.
* @param {CanvasTextProperties} properties - An object containing properties for the text, such as font size, style, and alignment.
* @returns {void}
*/
export function drawText(ctx, lines, x, y, properties) {
ctx.save();
const [textWidth, , lineHeight] = getTextBounds(ctx, lines, properties);
lines.forEach((l, i) => {
var _a, _b, _c;
const lineWidth = ctx.measureText(l).width;
const alignedX = alignCanvasText(x, textWidth, lineWidth, (_a = properties.textAlign) !== null && _a !== void 0 ? _a : 'left');
if (properties.textStyle && properties.textStyle.underline) {
underlineText(ctx, l, alignedX, y + lineHeight * i, (_b = properties.textFill) !== null && _b !== void 0 ? _b : '', (_c = properties.textSize) !== null && _c !== void 0 ? _c : '');
}
ctx.fillText(l, alignedX, y + lineHeight * i);
});
ctx.restore();
}
/**
* Aligns canvas text based on the given parameters.
* @param {number} originalCoordinate - The original coordinate of the text.
* @param {number} maxWidth - The maximum width of the text.
* @param {number} textWidth - The width of the text.
* @param {CanvasTextAlignment} alignment - The alignment of the text.
* @returns {number} - The aligned coordinate of the text.
*/
function alignCanvasText(originalCoordinate, maxWidth, textWidth, alignment) {
switch (alignment) {
case 'left':
return originalCoordinate;
case 'right':
return originalCoordinate + maxWidth - textWidth;
default:
return originalCoordinate;
}
}
/**
* Draws an underline below the given text on a canvas context.
* @param {CanvasRenderingContext2D} ctx - The canvas context to draw on.
* @param {string} text - The text to underline.
* @param {number} x - The x-coordinate of the starting point of the text.
* @param {number} y - The y-coordinate of the starting point of the text.
* @param {string} color - The color of the underline.
* @param {string} textSize - The size of the text in pixels.
*/
export function underlineText(ctx, text, x, y, color, textSize) {
ctx.save();
const textWidth = ctx.measureText(text).width;
const startX = x;
const endX = x + textWidth;
const startY = y + 2; // shifts underline 2px lower than the text
const endY = startY;
let underlineHeight = parseInt(textSize, 10) / 15;
if (underlineHeight < 1) {
underlineHeight = 1;
}
ctx.beginPath();
ctx.strokeStyle = color;
ctx.lineWidth = underlineHeight;
ctx.moveTo(startX, startY);
ctx.lineTo(endX, endY);
ctx.stroke();
ctx.restore();
}
/**
* Returns a string with the font size in pixels.
*
* @param {number} fontSize - The font size in points.
* @returns {string} The font size in pixels as a string.
*/
export function getFontSizeInPx(fontSize) {
return `${fontSize}px`;
}
export function getLabelTextColorByBackgroundColor(bgColor, textColor, invertedTextColor) {
const rgb = Color.rgb(bgColor).array();
const r = rgb[0];
const g = rgb[1];
const b = rgb[2];
const yiq = (r * 299 + g * 587 + b * 114) / 1000;
return yiq < 128 ? textColor : invertedTextColor;
}