How to split string into words but saving the initial word position

Hi! I want to build a sketch where I draw text to the screen as it normally works, as a block of text, but then I want each word to behave separately. At first, I thought it would be easy, just using the spliString function, but then I realized that this just split the string and there is no way to save the word’s initial positioning. For you to understand, in my sketch I want the words to repel from the cursor as I move it, but returning to the original position, for that I need to have an array storing all the original positions of the words, but splitting the text will only convert it into an array of words with undefined positions. Is it possible to do so? even if it is with some tricky way, like drawing the text first just to store the positions and then draw it again with the words split, or using some library…
I don’t have any code yet, because i don’t know where to start, but i don’t expect any code either, i just want to know if is possible and with which tool i can do it! Thanks in advance! I’ll upload a file to make it easier to understand what i want (the problem is not the repel part, at least for now :joy: ) https://imgur.com/wlIYwo3

You may need to create a class which would store those original coordinate pairs for each word.

I’m not good w/ typography, but I believe you should take a look at these 3 functions below in order to calculate those original coordinate pairs:

  1. p5js.org/reference/#/p5/textWidth
  2. p5js.org/reference/#/p5/textAscent
  3. p5js.org/reference/#/p5/textDescent

And although in Java syntax, here’s some silly “Bouncy Words” sketch:
Studio.ProcessingTogether.com/sp/pad/export/ro.9eHY5Fel1e0Jr

1 Like

thanks for the help! i will see what i can do with these links! the problem with the last one, although is pretty cool, is that you are setting the words initial position separate, which is the opposite of what i´m looking for. Thank you very much!

You can manually lay out the text and store its position to retrieve later. And as GoToLoop suggested, with class/object, we can easily control many variables.
For repelling part, Nature of Code will be a great resource.
Here is my code. hope this will work as a starting point.

        const str = `Lorem ipsum dolor sit, natus ex aliquid at porro illo sit beatae. Quae quibusdam quo quisquam omnis obcaecati nesciunt numquam! Commodquo quisquam omnis obcaecati nesciunt numquam! Commodquo quisquam omnis obcaecati nesciunt numquam! Commodquo quisquam omnis obcaecati nesciunt numquam! Commodquo quisquam omnis obcaecati nesciunt numquam! Commodi fugiat quod doloribus veniam,`
        const words = [] // Word objects

        function setup() {
            createCanvas(500, 500)

            textFont('serif')
            textSize(24)
            textAlign(LEFT, TOP)

            const wordsStr = str.split(' ')
            const xmargin = 40
            const leading = 30
            let x = xmargin
            let y = 60
            for (let i = 0; i < wordsStr.length; i++) {
                const wordStr = wordsStr[i]
                const wordStrWidth = textWidth(wordStr)
                const word = new Word(wordStr, x, y, i)
                words.push(word)
                x += wordStrWidth + textWidth(' ')
                if (x > width - (xmargin + wordStrWidth)) {
                    x = xmargin
                    y += leading
                }
            }
        }

        function draw() {
            background(220)

            for (let i = 0; i < words.length; i++) {
                const word = words[i]
                word.update()
                word.display()
            }
        }

        class Word {
            constructor(word, x, y, idx) {
                this.word = word
                this.x = x
                this.y = y
                this.idx = idx
            }

            update() {
                this.y = this.y + sin(this.idx/2. + frameCount/10.)/2
            }

            display() {
                fill(0)
                noStroke()
                text(this.word, this.x, this.y)
            }
        }
2 Likes

Pure Gold!
I was wondering how to use the TextWidth to do what i wanted, but i was struggling with the spaces, and the different lines, but this
words.push(word) x += wordStrWidth + textWidth(' ')
is an awesome solution! thank you very much!

2 Likes