ChatGPT解决这个技术问题 Extra ChatGPT

Split string in JavaScript and detect line break

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?

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.
hmm, okay i'll have to re-strategise things. And theres no way to simply "move" a text area into a canvas?
You should put your solution into an answer and accept it, instead of putting it in the question.
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: As Jean-Paul already told you, the answer includes both a non-jQuery solution and a jQuery solution.

J
Jean-Paul

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);

Hope that helps!


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.Serp Good addition.
Down-voted for answering a JavaScript question with jQuery. Dependencies are weaknesses and only slow the overall UX down.
@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.
@S.Serp str.split(/\r\n|\r|\n/g) if you also have \r only line breaks (like I )did
T
Tính Ngô Quang

Split string in JavaScript

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

OR

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

https://i.stack.imgur.com/vjU9C.png


I suppose the second one is better for this purpose (splitting). Isn't it?
Yes, split faster
p
profimedica

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');

https://i.stack.imgur.com/2b9MR.png


m
martin

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;
    }

A
Ann Zen

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

yourString.split("\n")

P
Peter Mortensen

You should try detect the first line.

Then the:

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

I'm not sure, but maybe it helps.


j
jacksondc

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);
  }