Showing posts with label text. Show all posts
Showing posts with label text. Show all posts

Friday, 6 January 2023

Getting the position of a character in a text object in CreateJS

 For those of us who are accustomed to Flash, if we wanted to know the exact x,y coordinates of a character in a textbox, using AS3, we could use the getCharBoundaries function, which if I remember correctly, would return a Rectangle object with the x, y, width and height... I think? The point is, there was a built-in method to do it.

Such a function does not exist in CreateJS (or I couldn't find one).

I was trying to make a little missing-words-type activity, and I wanted users to select the word they were dealing with (could this have been done in HTML with less bother? Probably, I dunno) - so I needed to make a button that would go behind the part of the textbox where the specific word was created.

When I saw that CreateJS did not have an equivalent of the getCharBoundaries function in AS3, I was ready to give up and try an alternative approach. But then I remembered that there are monospaced fonts such as Courier New, that we use in biosciences so that DNA and protein sequences are easy to read. If I used one of those (please skip to the code excerpt(s) below if you aren't interested in the evolution of this, I just really enjoyed this little problem-solving journey, personally), I reasoned, then as long as I knew where the text started, I might be able to figure out the location of each letter, though working out where the line breaks were would be a pain.

On the stage, I manually measured the width of each letter (I realised later a better way of doing this, see below) at 21.6px in the font and size I was using. I used this letter width and the index of the character in the text to position a movieclip relative to the text area.

There were two empty movieclips on stage, the one on top (loadIt) was for loading the dynamic text, the one underneath (loadItBtn) was for loading the buttons.

It went something like this (just focusing on how to deal with a single line first):

tx = new createjs.Text('Hello _____.''36px Courier New','black');
this.loadIt.addChild(tx);

this.letterWidth = 21.6;//I measured this on the stage manually...blech
for(i=6; i<11; i++) {
	btn = new lib.btnMC();//this is just a rectangle made to match the height of the line, and the width of the letters.
	btn.x = i * this.letterWidth;
	this.loadItBtn.addChild(btn);
}

So, some useful functions: tx.getMeasuredWidth() could tell me how wide the text area was, as I was using short paragraphs. I would then use tx.lineWidth, to set how wide I wanted the text area to be, which would cause word wrapping. I would then use tx.getMeasuredHeight() to find out the height of the text area so I could position it on the canvas (you can use a function to get or set your lineHeight).

However, what if the text ends up with multiple lines? Enter (drumroll) getMetrics()!

This function will give you an array, called 'lines', which tells you what text is in each line! So I wrote a loop to check whether the index of the character in the text could be found in the line of the array. Then adjusted the y coordinate of the buttons I was adding based on that. Then I had to remember to figure out what the index of my character was in the line of the text, and use that as the x coordinate.

I won't go into all the details, but if you use console.log(text_name.getMetrics());, you can see the output for yourself in the console.


ISSUES:

1) Using scaleX to size an mc to match the word width did not work for me, it doesn't seem to be very accurate. I dealt with this by making a movieclip that was the perfect size and adding it multiple times, but a better solution would have been to draw a rectangle of the correct size.

2) Measuring the letter width manually is a pain, but manageable because you only need to do it once, but then you have to stick to that font size. I realised later that you could write a function to create a text area, add some text and measure the width to calculate the width of a single letter. Then I realised that actually, you could do this for any font! You'd have to make sure you measured every type of letter you were planning to use, and punctuation, but you could easily create an object that stores the widths of the characters you are using. Easily-ish. But basically, it means that you could work out the position of letters in text areas, and such a function would require some alteration if the text was left-, centre- or right-justified, and it would probably only shorten your life-span by a few years... But, yeah, doable.

You can see an example of what I was aiming for here: Missing words exercise

Have a nice day!

Thursday, 2 May 2013

TweenJS: Changing Text

This isn't really tweening, just looping a text change.


Line 13: Because the text is center aligned, if you were to set its x property to 0, you would only see half the text.

Line 18: I have made the outline of the rectangle, and have not filled it in. I have also used to getMeasuredWidth/Height() to get the rough dimensions of the text - although what I really need is the dimensions of the text I will change it too, oh well...

Lines 19 and 20: Just positioning the box so it will be around the text.

Line 25: Changes the text after 1 second, no tweening involved. set() is used to change a property of the box, if you don't say which object is supposed to be affected, it assumes it is the object of the tween. Also, wait() is used because otherwise it loops back to the beginning so fast, you can't see the change. Please note, that the highlight box doesn't change back to invisible, this is because the original invisible setting is not part of the looping tween.

Monday, 29 April 2013

EaselJS: Hit Areas

Hit Areas are areas that allow will respond for an object, for mouse events, such as clicks or mouseovers. This is especially useful for text, which will otherwise only respond if you directly hit the pixels that make up the letters.

1) Mouseovers are expensive for the CPU, so are diabled by default. The lower the parameter, the less responsive the mouseover will be.
2) This is how to create a text label.
3) This is the shape that will act as the hit area.
4) getMeasured... is used to see how big the text is. I imagine the parameters are x, y, width, height.
5) When hit is used as a hitarea, it doesn't need to be added to the stage, it will still work. It also doesn't need to be given x and y coordinates, it is assumed to start off wherever the label does. If you give it x and y co-ordinates, they are relative to the position of the label the hitarea has been attached to. If you attach it to the stage, it will be visible, but it will still work.
6) The label doesn't need to be made a global variable, because it is a parameter of the evnt.
7) This changes the alpha dependent on what kind of mouseevent triggered it.
8) In the tutorial, the stage.update was attached to a tick event, but this works too.