Home > OS >  Using charAt to enumerate letters one by one in a loop, without getting stuck in a loop, in JavaScri
Using charAt to enumerate letters one by one in a loop, without getting stuck in a loop, in JavaScri

Time:12-06

This is my first post on here, hopefully I'm doing this right.

So my friend is trying to get this green raining Matrix code to rain a sentence instead of random letters.

html {
    background: black;
    height: 100%;
    overflow: hidden;
}

body {
    margin: 0;
    padding: 0;
    height: 100%;
}
const canvas = document.getElementById('Matrix');
const context = canvas.getContext('2d');

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;


const alphabet = "Where they at though?"

const fontSize = 16;
const columns = canvas.width/fontSize;

const rainDrops = [];

for( let x = 0; x < columns; x   ) {
    rainDrops[x] = 1;
}

const draw = () => {
    context.fillStyle = 'rgba(0, 0, 0, 0.05)';
    context.fillRect(0, 0, canvas.width, canvas.height);
    
    context.fillStyle = '#0F0';
    context.font = fontSize   'px monospace';

    for(let i = 0; i < rainDrops.length; i  )
    {
        const text = alphabet.charAt(Math.floor(Math.random() * alphabet.length));
        context.fillText(text, i*fontSize, rainDrops[i]*fontSize);
        
        if(rainDrops[i]*fontSize > canvas.height && Math.random() > 0.975){
            rainDrops[i] = 0;
        }
        rainDrops[i]  ;
    }
};

setInterval(draw, 30);

If you want to see it in action, here it is on CodePen.

I do understand a decent chunk of JavaScript, and I understand that how this works is that after setting the canvas width and height to the screen size, we set the fontSize to 16, and we divide the page into columns for the width of each letter. So we have a bunch of columns for the rain. Then those columns each have a rainDrops array index that each start with a value of 1 initially.

So on a 1080x1920 screen, there are 120 columns of rain, because 1920/16. In the draw function, which will be called every 30ms, the canvas is filled with an rgba value which is light grey. The font will be assigned 16px monospace green with hex #00FF00. In the for loop, rainDrops.length will be dependent on the number of columns that fit in the screen. 120 columns fit in a 1920 screen. So i will iterate to 120 in that case.

alphabet.length is 21 I believe, and the alphabet.charAt() method will look at the letter that is randomly chosen by (Math.floor(Math.random() * alphabet.length)). And this is where the problem is, actually. It's random here, and I'm trying to make it enumerate a sentence out of charAt selections, possibly with a forEach loop or spread operator or something, but nothing I've tried works.

fillText is how the letters get displayed in the way that they do. The first parameter takes a string for text, which is the letter. and then the code after that is what determines the strand effect. Parameters 2 and 3 are x and y positions, so it's (16px * array index) and (16px * index value) for i*fontSize and rainDrops[i]*fontSize. 16px * 120 = 1920 on a 1080p screen, filling the x axis. So it goes in the x parameter. So rainDrops[i]*fontSize is what makes the rain fall down. The "if" conditional determines if the rain has fallen too far and then sets index to zero to make it restart from the top.

And rainDrops[i] is what makes the 1 in every array index grow. They all grow simultaneously at first, that's why the rain all comes down together uniformly at first. The Math.random() in the conditional makes the rain come down more randomly later.

So I think I know how this code works. But I don't know how to get a clear sentence out instead of random letters. If someone could help, I would greatly appreciate it.

If I could make an enumeration loop but break out of it and increment the initializer I think that could do it. Otherwise it gets stuck in a loop that completes the sentence, but we're trying to get a single letter each time to feed the charAt method.

Sorry for writing a novel.

Edit: the rgba is used to create the fading letter shader effect, actually, I think, as it is the alpha, which is like transparency.

CodePudding user response:

In my comment on the original question, I suggested changing line 27 to this:

const text = alphabet.charAt((rainDrops[i]-1) % alphabet.length);

You can see it applied here.

The raindrops array contains integers that represent each stream of text's progress down the window, which may increase to a value beyond the length of the alphabet string. By using the modulo of the number of characters in the alphabet string, the value of text will loop through the string. I subtract 1 because the values in the raindrops array are initialised at 1, so the first character would be skipped if 1 was not subtracted.

  • Related