-
Notifications
You must be signed in to change notification settings - Fork 334
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Apply different font to each line in label annotation options #739
Comments
@antbankdata as you have seen, you can do it by a canvas or image and not configuring the plugin and not sure if this could be an enhancement to implement as common use case. Nevertheless I have prepared a codepen where, leveraging on the canvas, you could have a multi-line content with different font for each row. The |
@antbankdata FYI, I have created another codepen, https://codepen.io/stockinail/pen/MWQpZKb, changing the function to create the label by a canvas. Hopefully this solves your issue. // checks and gets the index
// when colors and fonts, passed as arguments are not the same length of the content length
const checkAndGetIndex = (i, array) => Math.max(0, Math.min(i, array.length - 1));
/**
* @param {string|string[]} content - text of the label
* @param {FontSpec|FontSpec[]} pfonts - the fonts to apply to each row of the content.
* If less than the content length, the last font object is used for the rest of the lines
* @param {Color|Color[]} [pcolors = ['black']] - the colors to apply to each row of the content.
* If less than the content length, the last color is used for the rest of the lines
* @param {LabelTextAlign} [textAlign = 'center'] - text alignment inside the canvas
* @returns {HTMLCanvasElement} the canvas to add to annotation label as content
*/
const createTextLabel = function(content, pfonts, pcolors = ['black'], textAlign = 'center') {
// check and normalize the arguments
const lines = Chart.helpers.isArray(content) ? content : [content];
const fonts = Chart.helpers.isArray(pfonts) ? pfonts : [pfonts];
const colors = Chart.helpers.isArray(pcolors) ? pcolors : [pcolors];
const toFonts = [];
fonts.forEach((el) => toFonts.push(Chart.helpers.toFont(el)));
// create canvas to return
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// calculate the size of the canvas
// based on content and fonts
const count = lines.length;
let width = 0;
let height = 0;
for (let i = 0; i < count; i++) {
const font = toFonts[checkAndGetIndex(i, toFonts)];
const text = lines[i];
ctx.font = font.string;
width = Math.max(width, ctx.measureText(text).width);
height += font.lineHeight;
}
canvas.width = width;
canvas.height = height;
// draw the text content on the canvas
ctx.save();
ctx.textBaseline = 'middle';
ctx.textAlign = textAlign;
let x = 0;
if (textAlign === 'center') {
x = width / 2;
} else if (textAlign === 'end' || textAlign === 'right') {
x = width;
}
let y = 0;
for (let i = 0; i < count; i++) {
const font = toFonts[checkAndGetIndex(i, toFonts)];
const lh = font.lineHeight;
y += lh / 2;
const text = lines[i];
ctx.fillStyle = colors[checkAndGetIndex(i, colors)];
ctx.font = font.string;
ctx.fillText(text, x, y);
y += lh / 2;
}
ctx.restore();
return canvas;
}; @kurkle @LeeLenaleee I was thinking to add a sample about this use case. Make sense to you? |
Feels a bit to complex to me to be used in an example. |
Anyway the code is written here therefore whoever can take and use it if wants. |
@stockiNail Thank you very much for the quick and detailed answer. I will likely implement some variation of this createTextLabel function. I do however still want to emphasize that i, as a consumer of the chartjs-plugin-annotation, would very much prefer to be able to implement it more elegantly, by just passing it as a property. |
@antbankdata yes, I just proposed a work-around so you are not stuck, if urgently needed. I have tagged this issue as In my opinion, going to a multiple fonts (and colors) for the labels, we could create a different way to manage labels comparing with Chart.js where a text can have only 1 font and color. It is only a doubt as it can be implemented externally. @kurkle @LeeLenaleee what do you think? |
I am bit scared for the rabit hole you can open with this. Like for this use case you only need to be able to style individual lines. But what happens if someone wants to style indevidual words or even individual letters. Need to give the current text render implementation a good look but I think it will be a pain in the ass to make it work nicely |
@stockiNail When i try to implement the canvas solution, the text becomes a little blurry (at font size 12). I have tried several solutions online to make the text less blurry (using devicePixelRatio), however, it remains blurry. Do you know if it is possible to fix the blur issue, or if that is just the downside of using canvas? You can see the issue in your newest codepen if you change the font size to 12 and size of the chart to 300x200. |
@antbankdata I think that it may be due to the width and height values which are set to canvas dimension (and automatically rounded to an integer). Can you try the following? ...
canvas.width = Math.ceil(width);
canvas.height = Math.ceil(height);
... I have changed the the codepen and, if I'm not wrong, sounds a bit better. |
Hi,
I am trying to create the following label in my graph:
![image](https://user-images.githubusercontent.com/99955097/168798588-c5188496-6b52-41e6-8c95-d4784efb7f26.png)
I am, however, unable to make the second line bold, unless i either create 2 labels or create a canvas (which doesn't scale very well).
Would it be possible to change the font parameter to accept a list of FontSpec? Or possibly change content, such that you can pass text styling options alongside the text?
The text was updated successfully, but these errors were encountered: