96

I have a small function I found that takes a string from a textarea and then puts it into a canvas element and wraps the text when the line gets too long. But it doesn't detect line breaks. This is what it's doing and what it should do:

Input:

Hello

This is dummy text that could be inside the text area.
It will then get put into the canvas.

Wrong output:

Hello this is dummy text
that could be inside the
text area. It will then
get put into the canvas.

What it should output:

Hello

This is dummy text that
could be inside the text
area. It will then get
put into the canvas.

This is the function I'm using:

function wrapText(context, text, x, y, maxWidth, lineHeight) {
    var words = text.split(' ');
    var line = '';

    for(var n = 0; n < words.length; n++) {
        var testLine = line + words[n] + ' ';
        var metrics = context.measureText(testLine);
        var testWidth = metrics.width;
        if (testWidth > maxWidth && n > 0) {
            context.fillText(line, x, y);
            line = words[n] + ' ';
            y += lineHeight;
        }
        else {
            line = testLine;
        }
    }
    context.fillText(line, x, y);
}

Is it possible to achieve what I'm trying to get? Or is there a way to simply move the text area as is into the canvas?

user2357112
  • 260,549
  • 28
  • 431
  • 505
Dustin Silk
  • 4,320
  • 5
  • 32
  • 48
  • 1
    Line breaks created by automatic text-wrapping can't be detected. If a textarea contains line breaks created by hitting `ENTER`, they can be found for example by splitting with `\n`. – Teemu Feb 11 '14 at 20:05
  • hmm, okay i'll have to re-strategise things. And theres no way to simply "move" a text area into a canvas? – Dustin Silk Feb 11 '14 at 20:08
  • 1
    You should put your solution into an answer and accept it, instead of putting it in the question. – jacksondc Jul 02 '14 at 18:44
  • 2
    Down-voted for accepting a jQuery answer for a JavaScript question. The web is full of people who have to `-jquery` *every* time we do a JavaScript search. ︎ – John May 13 '18 at 20:20
  • @John: As Jean-Paul already told you, the answer includes both a non-jQuery solution and a jQuery solution. – user2357112 May 14 '18 at 19:40
  • @John this was asked 4 years ago at the height of jquery. And the answer can easily be converted between the two since the real take away was the '\n'. – Dustin Silk May 15 '18 at 09:29
  • Possible duplicate of [How to detect line breaks in a text area input?](https://stackoverflow.com/questions/10950538/how-to-detect-line-breaks-in-a-text-area-input) – Kamal Nayan Jun 04 '19 at 10:06

7 Answers7

140

Using .split():

var str = `your text
           that spans
           multiple lines`

// Split the string on \n or \r characters
var separateLines = str.split(/\r?\n|\r|\n/g);

alert("Total number of separate lines is: " + separateLines.length);

Or using .match() instead:

var str = `your text
           that spans
           multiple lines`

// Split the string on \n or \r characters
var separateLines = str.match(/[^\r\n]+/g);
 
alert("Total number of separate lines is: " + separateLines.length);
starball
  • 20,030
  • 7
  • 43
  • 238
Jean-Paul
  • 19,910
  • 9
  • 62
  • 88
  • 54
    as a note: to get content of lines without newline char(s), we can use: `str.split(/\r?\n/g);` which works for `\r\n` and `\n` – S.Serpooshan Jan 22 '17 at 09:33
  • 1
    @S.Serp Good addition. – Jean-Paul Jan 22 '17 at 09:39
  • 14
    Down-voted for answering **a JavaScript question with jQuery**. Dependencies are weaknesses and only slow the overall UX down. – John Aug 15 '17 at 07:25
  • 6
    @John Even though dependencies *can be* weaknesses, programming is always a trade-off between concise code and good performance. In this case, the question can be answered in two ways: using plain JavaScript and using jQuery. I gave the answers for both. It is up to the OP to decide which implementation to follow. Given that I show both approaches in my answer, your downvote seems unnecessary. But to each his own opinion. – Jean-Paul Aug 18 '17 at 07:14
  • 10
    @S.Serp `str.split(/\r\n|\r|\n/g)` if you also have `\r` only line breaks (like I )did – Xenos May 14 '18 at 14:51
  • 1
    Seconding Jean-Paul's comment. If javascript is provided, a jquery alternative is acceptable. But it's worth noting that John has a point, even if a bit knee-jerk. There are plenty of circumstances where requiring jQuery is not ideal (or even not even possible). – lilHar Nov 13 '18 at 22:08
53

Split string in JavaScript

var array = str.match(/[^\r\n]+/g);

OR

var array = str.split(/\r?\n/);

Performance

Tính Ngô Quang
  • 4,400
  • 1
  • 33
  • 33
6

In case you need to split a string from your JSON, the string has the \n special character replaced with \\n.

Split string by newline:

Result.split('\n');

Split string received in JSON, where special character \n was replaced with \\n during JSON.stringify(in javascript) or json.json_encode(in PHP). So, if you have your string in a AJAX response, it was processed for transportation. and if it is not decoded, it will sill have the \n replaced with \\n** and you need to use:

Result.split('\\n');

Note that the debugger tools from your browser might not show this aspect as you was expecting, but you can see that splitting by \\n resulted in 2 entries as I need in my case: enter image description here

profimedica
  • 2,716
  • 31
  • 41
3

This is what I used to print text to a canvas. The input is not coming from a textarea, but from input and I'm only splitting by space. Definitely not perfect, but works for my case. It returns the lines in an array:

splitTextToLines: function (text) {
        var idealSplit = 7,
            maxSplit = 20,
            lineCounter = 0,
            lineIndex = 0,
            lines = [""],
            ch, i;

        for (i = 0; i < text.length; i++) {
            ch = text[i];
            if ((lineCounter >= idealSplit && ch === " ") || lineCounter >= maxSplit) {
                ch = "";
                lineCounter = -1;
                lineIndex++;
                lines.push("");
            }
            lines[lineIndex] += ch;
            lineCounter++;
        }

        return lines;
    }
martin
  • 56
  • 1
  • 5
2

You can use the split() function to break input on the basis of line break.

yourString.split("\n")
Red
  • 26,798
  • 7
  • 36
  • 58
sau0409
  • 153
  • 1
  • 5
1

You should try detect the first line.

Then the:

if(n == 0){
  line = words[n]+"\n";
}

I'm not sure, but maybe it helps.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Netzach
  • 321
  • 2
  • 13
0

Here's the final code I [OP] used. Probably not best practice, but it worked.

function wrapText(context, text, x, y, maxWidth, lineHeight) {

    var breaks = text.split('\n');
    var newLines = "";
    for(var i = 0; i < breaks.length; i ++){
      newLines = newLines + breaks[i] + ' breakLine ';
    }

    var words = newLines.split(' ');
    var line = '';
    console.log(words);
    for(var n = 0; n < words.length; n++) {
      if(words[n] != 'breakLine'){
        var testLine = line + words[n] + ' ';
        var metrics = context.measureText(testLine);
        var testWidth = metrics.width;
        if (testWidth > maxWidth && n > 0) {
          context.fillText(line, x, y);
          line = words[n] + ' ';
          y += lineHeight;
        }
        else {
          line = testLine;
        }
      }else{
          context.fillText(line, x, y);
          line = '';
          y += lineHeight;
      }
    }
    context.fillText(line, x, y);
  }
jacksondc
  • 600
  • 1
  • 6
  • 19