Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

html canvas text overflow ellipsis

Is it possible to draw text on a canvas that has an ellipsis at the end of the text if the text won't fit in the available width and needs to be truncated? Thanks.

like image 870
brad miley Avatar asked May 09 '12 02:05

brad miley


People also ask

How do I force text-overflow ellipsis?

Inline overflow occurs when the text in a line overflows the available width without a breaking opportunity. To force overflow to occur and ellipses to be applied, the author must apply the nowrap value to the white-space property on the element, or wrap the content in a <NOBR> tag.

How do I stop Div text-overflow?

To fix this problem, avoid using vw for your max-width and use a max-width of 100% instead. This will transfer the width of the parent container to the width of the child container.

Why is ellipsis not working CSS?

So, if you've arrived at this question because you're having difficulties getting the ellipsis to operate inside a display: Try adding min-width: 0 to the outmost container that's overflowing its parent, even if you've previously set overflow: hidden to it, and see how it works for you.

Why does text-overflow ellipsis doesn't work?

text-overflow: ellipsis only works when the following is true: Parent element is not set to display: inline (span's default,) You must use display: block or display: inline-block. The element's width must be constrained in px (pixels) – it doesn't work with values specified using % (percent.)


2 Answers

Top voted answer causes performance issue when working with large number of text.

Here's adapted version using binary search to speed up the search for right length of string.

const binarySearch = ({ max, getValue, match }) => {
  let min = 0;

  while (min <= max) {
    let guess = Math.floor((min + max) / 2);
    const compareVal = getValue(guess);

    if (compareVal === match) return guess;
    if (compareVal < match) min = guess + 1;
    else max = guess - 1;
  }

  return max;
};

const fitString = (
  ctx,
  str,
  maxWidth,
) => {
  let width = ctx.measureText(str).width;
  const ellipsis = '…';
  const ellipsisWidth = ctx.measureText(ellipsis).width;
  if (width <= maxWidth || width <= ellipsisWidth) {
    return str;
  }

  const index = binarySearch({
    max: str.length,
    getValue: guess => ctx.measureText(str.substring(0, guess)).width,
    match: maxWidth - ellipsisWidth,
  });

  return str.substring(0, index) + ellipsis;
};
like image 150
yjcxy12 Avatar answered Oct 15 '22 10:10

yjcxy12


There is no standard function.

As I needed one, I made this small function that computes the best fitting string :

function fittingString(c, str, maxWidth) {
  var width = c.measureText(str).width;
  var ellipsis = '…';
  var ellipsisWidth = c.measureText(ellipsis).width;
  if (width<=maxWidth || width<=ellipsisWidth) {
    return str;
  } else {
    var len = str.length;
    while (width>=maxWidth-ellipsisWidth && len-->0) {
      str = str.substring(0, len);
      width = c.measureText(str).width;
    }
    return str+ellipsis;
  }
}

where c is the 2D context.

You can draw the string normally after having set your font and other drawing parameters of your canvas :

c.fillText(fittingString(c, "A big string that will likely be truncated", 100), 50, 50);
like image 32
Denys Séguret Avatar answered Oct 15 '22 09:10

Denys Séguret