Is it possible to set multiple colours within a single function?

edited December 2016 in How To...

Hi everyone.

Basically I am using string arrays to generate a piece of text randomly and am calling them into a text function by writing;

text(sentences1[n] + sentences2[m], 400, 400);

Is there any way of colouring the output of each array with a different colour? So that one sentence could be blue and the next red for example?

Answers

  • edited March 2018

    You need to call fill() before each array element. The following is an example of the concept:

    String[] sentences={"I drink coffee","I drink coffee","I drink coffee","I drink coffee","I drink coffee","I drink coffee","I drink coffee","I drink coffee"};
    
    void setup(){
     size(800,800);
    }
    
    void draw() {
      background(92);
      for (int i=0; i<sentences.length; i++) {
        fill(random(256));
        text(sentences[0], 400, map(i, 0, sentences.length, 10, height-10));
      }
    }
    

    For the map function, I am printing all the array items across the height of the screen, with a margin of 10 pixels.

    Kf

    Keyword: kf_keyword text textbox improved text feature

  • Ok, so how would I be able to get the sentences from the second array to fit onto the end of the ones of the first array. Considering my sentences are of different lengths and I want them to fit into a paragraph seamlessly.

    Thanks for the help!

  • You can use textWidth() to find out the width of a string with current font and fontsize settings. Here is an example:

    String[] sentences={"I drink coffee. ", "I drink tea."};
    
    void setup() {
      size(800, 800);
      textSize(30);
    }
    
    void draw() {
      background(92);
      drawText(sentences[0], 0xffff0000, sentences[1], 0xff00ff00, mouseX, mouseY);
    }
    
    void drawText(String txt1, int col1, String txt2, int col2, int x, int y) {
      fill(col1);
      text(txt1, x, y);
      fill(col2);
      text(txt2, x+textWidth(txt1), y);
    }
    

    Getting a little more complex, if you have multiple lines and ant to handle word-wrapping. But this might be a starting point.

  • edited November 2016

    Thanks for the reply.

    This is very helpful to see, but you were spot on about having multiple lines. If I attempt to make the sentences longer there is no way I can see of having the second sentence continue on the line bellow, as each text function within the drawText function is treated as separate.

    ProcessingProblem

    I get the effect above.

    Any thoughts on fixing this?

    Thanks!

  • edited November 2016

    Ok so this is my code so far...

    `` int n;

    int m;

    int time = millis();

    float wait1 = random(3000, 4000);

    float wait2 = random(3000, 4000);

    String [] sentences1 = { "And the man said that he wasnt happy.", "We Travelled three thousand miles.", "God sent to us a blessing that shook the ground.", "To dwell in compassion is the absolute." };

    String[] sentences2 = {" Forward to victory over the pigs!", " Do not march quickly toward the valley of damnation", " Lucozade is arrogant"};

    void setup() { background(0); fullScreen();

    }

    void draw() {

    background(0);

    if(millis() - time >= wait1){
    n = int(random(3)); / time = millis();

    }

    if(millis() - time >= wait2){ m = int(random(2)); time = millis();

    }

    textSize(26); text(sentences1[n] + sentences2[m],width/3, height/3, 400, 400);

    }``

    The sentences are just random nonsense, but what I am aiming for is to have the sentences from different arrays have different colours.

  • edited November 2016

    My approach:

    • First, check if the whole sentence can fit.(Use textWidth()).
    • If it fits, there is no problem.
    • If not, you now have two problems-
      • Firstly, you have to shift the required amount to the next line.
      • Secondly, you have to shift each of your later sentences a line down each.
    • To calculate required amount, I guess you must use textWidth() for each word starting from the last word in the sentence, till it fits.
    • Then, whatever is left over, add it to the array (though I'd rather use ArrayList) at the next to current index (use splice()).

    Try implementing it yourself, and tell us about the results.

  • Would this work using a randomised array ? So if I am randomly getting sentences of different lengths from the array. Is this method not contingent on the selection remaining the same?

  • edited November 2016

    @jabobob -- The left margin problem means that you can't allow line wrapping, ever. Instead you probably need to implement text wrapping for single-line text() blocks using a bricklaying algorithm with partial-bricks.

    For example:

    Edit: simplified this for clarity

    1. Given a collection of sentences, split each sentence on whitespace.
    2. Create a list of one-word text() bricks. Each word will be printed with the color of its sentence.
    3. Stack bricks along the line until the next brick would go off the edge of the right margin.
    4. Move to the next line, and continue.

    This should with text of any length, although the checking method is really inefficient if all your text is paragraph length -- in that case you might want to pre-chunk your text or do a better pre-approximation of line length.

    Or, to make all of this much much less fiddly, use a fixed-distance font.

  • textvisualidea

    This is my visually desired goal, with the sentences being pulled randomly from arrays at time intervals.

  • @jabobob -- right, that's why I described text wrap through bricklaying. That should solve your problem. I've updated my description above to simplify it, so that you aren't dynamically searching for wrap points -- instead you are printing each word with a separate call to text().

    Your example screenshot includes dynamic in-word hyphenation. Implementing rules for acceptable hyphenation is going to be a bit tricky -- you might want to add it after everything else works.

  • Thanks for the help, guna try to figure this out and see what I can come up with.

  • @jeremydouglass - What would you recommend is "acceptable" in-word hyphenation?

  • edited December 2016

    @Lord_of_the_Galaxy -- automatic hyphenation is hard. There are many rules in English, and one rule in "between syllables" -- and English syllable detection is very hard to code! For example, you can only break the word "syllables" like this:

    • sylla- bles

    ...but not like this:

    • syllab- les

    https://www.howmanysyllables.com/words/syllables

    For a small art project with a limited number of sentences you might just keep a lookup list of every word in the project text and how it could be hyphenated. Or you could just do the hyphenation wrong by breaking words at arbitrary letter lengths. However, this will create "bad breaks" like:

    • h- yphenated
    • hyphenate -d
    • hyp- henated

    If that isn't a big problem, then hyphenation can be relatively simple. If it is a problem, it is complex, and even professional auto-hyphenation software often gets it wrong.

    The RiTa library might have some tools to help with this? I'm not sure.

  • edited December 2016

    @jeremydouglass I didn't know that hyphenation is so complex. Isn't it amazing how we can do it without much thought.....

  • No hyphenation, but I ran a test and this is definitely doable otherwise, using the approach exactly as described by either @Lord_of_the_Galaxy or me. @jabobob, feel free to share your latest progress for feedback -- and be sure to format your code

    SentenceColoredText--screenshot

  • Looks beautiful. Could try implementing with hyphenation? Thanks in advance.

  • Im still struggling to work it out, ive created a brick laying structure for sentences but I am trying to figure out how to increment the position of individual words from a list without the code being too long. This is my first project in programming so im learning as I go. You got any more tips?

    I'll post my code so far tonight.

  • edited December 2016

    This is where I am at with it, I dont know whether this is the fastest way to do it or not but its working using a couple sentences. I know that this wont work with an array of sentences that are longer than a line, which is what I am aiming for, so I am far from finishing.

            int n = int(random(7));
            int m = int(random(0, 2));
    
            String[] sentences={"I drink coffee", "I drink coffee", "I drink coffee twice", "I drink coffee thrice", "I drink coffee four times", "I drink coffee five times", "I drink coffee sixths", "I drink coffee"};
            String[] sentences1={"hello hello hello adas fa f dsf sf af asdf dsd ag sadg ads f asddg asf adf asd f", "bye bye bye bye bye bye bye bye"};
            String[] list = split(sentences[n], " ");
            String[] list1 = split(sentences1[m], " ");
    
    
            float a ;
            float b;
            float xPos = 300;
            float yPos = 300;
            float xPos2 =300;
            float yPos2 = 300;
    
            void setup() {
              size(800, 800);
            }
    
            void draw() {
    
    
              background(92);
              for (int i=0; i <list.length; i++) {
    
                a = textWidth(list[i]); 
                {
                  fill(255, 0, 0);
                  text(list[i], xPos, yPos, a*4, 20);
                  println(a);
    
                  if (a<10) {
                    a = a + 5;
                  }
                  xPos = xPos +a;
                }
              }
              xPos = 300;
    
              for (int i=0; i<list1.length; i++) { 
    
                float a1 = textWidth(sentences[n]);
    
                b = textWidth(list1[i]); 
                {
                  fill(0, 255, 0);
                  text(list1[i], xPos2+a1, yPos2, b*12, 20);
    
                  xPos2=xPos2 +b;
                }
    
                if (xPos2+a1>width/1.2) {
                  yPos2 = 300 +15;
                  xPos2 = 300-a1;
                }
              }
              xPos2 = 300;
              yPos2 = 300;
    
    
    
    
    
    
              line(300+textWidth(sentences[0])*5, 0, 300+textWidth(sentences[0])*5, height);
            }
    

  • Any ideas on how to improve what I've done so far?

  • edited December 2016

    You should use splitTokens().

  • edited December 2016 Answer ✓

    Hmm.. not really sure that i understand everything you do there. Seems like too much hard-coded numbers involved. You don't need a 3rd and 4th parameter for text() here, because you want to handle line-breaks for yourself.

    Here is an example for only laying out one sentence into a paragraph. Maybe that is a starting point for you.

    void setup() {
      size(800, 800);
      translate(50, 50);
      fill(0);
      // a String
      String sentence = "Lorem ipsum dolor sit amet, consetetusa dipscin gelitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";
    
      // paragraph width
      int paraW = 400;
    
      // coordinates of current word
      int curX = 0;
      int curY = 0;
    
      // split string into words
      String[] words = sentence.split(" ");
    
    
      // iterate over all words of the sentence
      for (int i =0; i<words.length; i++ ) {
    
        // width of current word
        float wordW = textWidth(words[i]);
    
        // available space left for current line
        float widthAvailable = paraW -curX;
    
        // if it doesn't fit into current line
        if (wordW > widthAvailable) {
          // increase vertical position by line-height
          curY += textAscent()+ textDescent();
          // set horizontal position to 0
          curX = 0;
        }
        // draw the word at current position (and add a "space")
        text((words[i]+" "), curX, curY);
    
        // add the word-width to current x-position (don'T forget the " ")
        curX += textWidth((words[i]+" "));
      }
    }
    
  • edited December 2016

    Ok thanks @benja im going to take a look at your code and compare to mine as I actually have it working. Ive probably used a really overly complicated method. Still i've learnt a lot in the process of this! firstworking

  • It is working, isn't it?

  • Glad to hear it worked out, @jabobob! Re:

    I've probably used a really overly complicated method

    If you are willing to share your solution I'm happy to give feedback -- and/or share my solution if you would also like to see it.

  • Also, if you are still looking to add hyphenation of your strings through an external library, I recently learned that there is a Java implementation of a hyphenation algorithm available here:

    https://github.com/mfietz/JHyphenator

    It returns a list of valid break-points in words based on the language you select. If you are doing word-at-a-time parsing, you can then break the word at a breakpoint -- or just line-wrap at the word if it doesn't have any breakpoints.

  • I'm assuming that the library can take a word as input and provide as output the set of points at which the word can be hyphenated. Is that right?

  • That's right. I haven't tested it, but Hyphenator.hyphenate(word) "Returns a list of syllables that indicates at which points the word can be broken with a hyphen."

    https://github.com/mfietz/JHyphenator/blob/master/src/main/java/de/mfietz/jhyphenator/Hyphenator.java

    Note that if you are using p5 instead of Java Processing you can also do this with the "nlp-compromise" library.

  • edited February 2017

    Because of recent interest from new users I'm sharing an example sketch, SentenceColoredText.pde, with a simple example function sentenceBox that handles the per-word layout and the changing color.

    This general approach could be adapted to work with words and phrases rather than sentence, and to handle bold, italics, text size, keyword highlighting, etc. rather than color.

    See the screenshot above: https://forum.processing.org/two/discussion/comment/80952/#Comment_80952

    /**
     * Sentence Colored Text
     * color each sentence in a list differently
     * while performing correct text wrapping.
     * @ since 2016-12-01
     * @ author Jeremy Douglass
     * Processing 3.2.3
     * https: //forum.processing.org/two/discussion/comment/80886/
     */
    
    String[] sentences = {
      "Lorem ipsum dolor sit amet.", 
      "Consectetur adipiscing elit.", 
      "Sed do eiusmod tempor incididunt, ut labore et dolore magna aliqua.", 
      "Ut enim ad minim veniam.",
      "Quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
      "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",
      "Excepteur sint occaecat cupidatat non proident.",
      "Sunt in culpa qui officia deserunt mollit anim id est laborum.",
      "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.",
      "Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.",
      "Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem."
    };
    String[] sentenceSet;
    float TEXTSIZE = 16;
    float MARGIN = 40;
    
    void setup() {
      size(400, 400);
      frameRate(1);
    }
    
    void draw() {
      background(0);
      // select a number of sentences to display based on time
      sentenceSet = subset(sentences, 0, second()%sentences.length);
      // draw colored sentences in a box
      sentenceBox(sentenceSet, MARGIN, MARGIN, width-MARGIN-3, height-2*MARGIN, TEXTSIZE);
    }
    
    void sentenceBox(String[] sentences, float x, float y, float w, float h, float tsize){
      String[] words;
      float spacing = tsize/5;
      float leading = tsize/4;
      float xoffset = x;
      float yoffset = y + tsize + leading;
      // bounding box
      pushStyle();
        fill(0); stroke(32);
        rect(x,y,w,h);
      popStyle();
      // look through sentences, random color each
      for (String sentence : sentences) {
        pushStyle();
        textSize(tsize);
        colorMode(HSB, 360, 1, 1);
        fill( random(360), 1, 1);
        words = split(sentence, " ");
        // loop through words, move to next line if a word won't fit
        for (String word : words) {
          if (xoffset + textWidth(word) > w) {
            xoffset = x;
            yoffset = yoffset + tsize + leading;
            // stopping printing lines beyond the bottom of the box
            if (yoffset > h + tsize + leading ){
              break;
            }
          }
          text(word, xoffset, yoffset);
          xoffset = xoffset + spacing + textWidth(word);
          println(word);
        }
        popStyle();
      }
    }
    
  • edited March 2018
Sign In or Register to comment.