how to make dynamic text move to vertical center if only 1 line is left in AS3 - actionscript-3

Is there a way to move dynamical text multiline to the center if there is only 1 line left, because veritcal center cannot be adjusted in the properties panel.
Image 3 Lines text and 1 line text

There's no default option for that, but you can emulate it.
// Let's assume this is your TextField you need to v-align.
var TF:TextField;
// Lets also assume that TextField is still in its original place.
// Record its upper Y-coordinate and height.
var atop:Number = TF.y;
var aheight:Number = TF.height;
// These lines instruct the TextField to adjust its lower
// border so that it exactly fits the text inside.
TF.wordWrap = true;
TF.autoSize = TextFieldAutoSize.LEFT;
// Now, math time.
// The difference between original height and new (autosized) height.
var adiff:Number = aheight - TF.height;
// To vertically position the resized TextField into the center of its original
// place, you need to shift it down by half of the height difference.
// It actually works if new height is larger than original too:
// the "adiff" value will be negative and it still works out.
TF.y = atop + adiff / 2;

Related

AS3 custom TextField text is being drawn outside its textWidth

So this one is a little hard to explain. I have a custom Text class that automatically resizes and sets the width of the text when you change its value. I then take that Text and draw it on a Bitmap to scale it up to make the text look pixelated.
I have a property called maxWidth that allows you to restrict the width of the text if you want it to maintain a certain width. By default the maxWidth is the width of the text's parent so that it doesn't get cut off or expand the parent's boundaries unexpectedly.
So unfortunately when I draw the text it sometimes gets cut off on the right side. Now I've checked all the values and the width and textWidth are showing up as within their maxWidth values, but when I take a look myself through screenshots I see the text is actually about 3 pixels wider than it should be.
Here's an image to better explain what I mean:
I turned on borders so you can easily see what I mean. The word "and" on the first line gets drawn outside its border. Here is the line of code that handles resizing text when you change its bounds.
override protected function checkResize(value:String):void {
var bufferWidth:uint = Math.floor(Number(defaultTextFormat.size) / bufferDivisor) + bufferMin;
var maxWidth:Number = this.maxWidth;
x = y = 0;
if (parent is Stage) {
var stageParent:Stage = Stage(parent);
super.width = stageParent.stageWidth;
super.height = stageParent.stageHeight;
if (maxWidth == 0) maxWidth = stageParent.stageWidth;
}
else {
super.width = parent.width;
super.height = parent.height;
if (maxWidth == 0) maxWidth = parent.width;
}
maxWidth = maxWidth / scale;
text = value;
if (textWidth + bufferWidth <= maxWidth) super.width = textWidth + bufferWidth;
else super.width = maxWidth;
super.height = textHeight + 4;
if (textSnapshot) updateSnapshot();
if (alignRelation) Align.alignTo(textSprite, alignRelation, alignDirection, alignXOffset, alignYOffest);
}
And for this text specifically the width value states it's 512, which is correct since that's the maxWidth. However if you notice the top line in the text, it goes beyond the 512 width border, it actually goes all the way to 515 even though it says its width is 512. Even more bizarre is the textWidth states it's 510.4 even though the first line goes well beyond that amount. I just want to know if I'm doing anything wrong or if there's a way to get a true textWidth value.
This seems to be related to embedding fonts, at least it was when I had the same problem. A workaround is to set the right margin of the text field, like so
var tf:TextFormat = new TextFormat();
tf.rightMargin = 10; // or whatever fixes your problem, e.g. relate it to font size
textField.setTextFormat(tf);

Setting an movieclips image/background

I have a button and a small area which is a movieclip.
What i need is, on button press it inserts an image into the movieClip, it would have to be docked into the whole movieclip area essentially.
I have looked through multiple posts yet they have an overwhelming amount of information that I cannot figure out, this is so far what i have done :
B_Background1.addEventListener(MouseEvent.CLICK, setBackground1);
function setBackground1(event:MouseEvent):void{
var firstPic:MovieClip = new C_1BackgroundPIC();
addChildAt(firstPic, C_MainStage);
}
As I understand it, it adds an event to the button, then in the function it creates a new movieClip instance which has the Picture inside of it, and then adds it to the "MainStage" although using C_MainStage is invalid thus doesn't work, it does add a picture if i just use 0 as the position but it then adds it to the position 0, which i dont want...
It's a good start. When you use addChildAt, it expects a number as the second parameter. Presumably, C_MainStage is your MovieClip (which isn't a number). Presumably you want the current display index of C_MainStage (not C_MainStage itself). This can be had by using getChildIndex
Look at the following:
function setBackground1(event:MouseEvent):void{
var firstPic:MovieClip = new C_1BackgroundPIC();
addChildAt(firstPic, getChildIndex(C_MainStage));
//now, you may need to also resize your picture so it fits in the bounds of C_MainStage, if so, you can do something like this:
if(firstPic.width >= firstPic.height){
//if firstPic is wider than it is tall
//set it's width to the same as C_MainStage
firstPic.width = C_MainStage.width;
//now, to keep the aspect ratio (in case they don't match), make the scaleY the same value as the new scaleX
firstPic.scaleY = firstPic.scaleX
}else{
//do the opposite as above since the height is larger than the width
firstPic.height = C_MainStage.height;
firstPic.scaleX = firstPic.scaleY;
}
//now, you may want to center firstPic in the C_MainStage bounds
firstPic.x = C_MainStage.x + ((C_MainStage.width - firstPic.width) * .5);
firstPic.y = C_MainStage.y + ((C_MainStage.height - firstPic.height) * .5)
}

HTML draw arrows behind text

Can html5 canvas do the following? If yes, how...
Be places behind bottom layer place behind HTML text
Can you accurately find the coordinates specified HTML texts (perhaps identified with span ID) regardless the of browser zoom size, or line wrap
I am trying to create the following with HTML/CSS/JS:
(please excuse the green squiggly underlines)
The highlighted text could obviously be set with background-color:
The tricky part is connecting the highlighted text with arrows, I would think it might be able to be done with HTLM canvas, but I am open to any ideas.
Also nice little bonus would be the have highlighting/arrows appear on hover or maybe on off button.
PS a little background, the text is some simplified JCL (sort of scripting language for Mainframes) and the highlighted items are files. I am attempting to make it easier to trace the data flow through a job (script). This is pretty simple version but many jobs can be 100s of lines long with lot details that make it hard to trace the which steps related to each other. If there other ideas or tools to help trace the data flow in JCL let me know.
//COBLPGM EXEC PGM=COBLPGM
//INPUT DD DSN=&&SORT,DISP=(OLD,DELETE)
//NACHA DD DSN=NODE.OPER.COBLPGM.OUT(+1)
//SORT2 EXEC PGM=SORT
//SORTIN DD DSN=NODE.OPER.COBLPGM.OUT(+1)
//SORTOUT DD DSN=&&SORT2,DISP=(,PASS)
//SYSIN DD DSN=NODE.OPER.PROCLIB(MEM)
//UNRELATE EXEC PGM=UNPGM
//INPUT DD DSN=NODE.OPER.UNRELATED.FILE
//REPORT DD DSN=&&REPORT
//TSTEMPT1 EXEC PGM=SPOPNCLO
//IN DD DSN=&&SORT2,DISP=(OLD,DELETE)
// IF TSTEMPT1.RC=0 THEN
//SORT3 EXEC PGM=SORT
//SORTIN DD DSN=NODE.OPER.COBLPGM.OUT(+1)
//SORTOUT DD DSN=&&SORT3,DISP=(,PASS),LRECL=141
//SYSIN DD DSN=NODE.OPER.CNTRLCDS(PARM)
// ENDIF
This is just a "conceptual" answer showing that you can track HTML to synchronize a canvas element.
The following code has the text itself in a <pre> tag in HTML. There is a canvas in the background set with fixed size. The canvas is updated on scrolling so the boxes are drawn relative to page (it should also be updated on resize, not shown).
As we can track the text you can see we would also be able to place any other graphics relative to it as well such as arrows and lines. I have not shown this here as I feel it would be too broad, but you should get the gist of it as it shows how to calculate the text line and char positions.
The basis is:
Get absolute position of the <pre> tag
Count number of lines (be careful to place text right after the tag and not on a new line, as well as placing end-tag at the same line as the last text-line)
Dividing absolute height on number of lines will give the line-height in pixels for each line
Use measureText() of context to measure the width of each line by setting context to use the same font and size as the <pre> tag
Use the rectangle from previous pre-tag to offset x and y for the line position.
Each char is calculate using the chars preceding the current, with measureText() (cell being this position and that of the next char).
The text is kept selectable with the canvas marking areas in the background.
Note that special chars in the text-line may throw off measureText (such as && in the example text). These chars must be encoded or replaced before measuring. Replacing is not a problem with a monospaced font such as in this case.
Demo
var pre = document.querySelector("pre"), // get pre ele,ent
rect = pre.getBoundingClientRect(), // get its absolute position
lines = pre.innerHTML.split("\n"), // split text lines
count = lines.length, // count lines
lineH = rect.height / count, // line height
canvas = document.querySelector("canvas"), // setup canvas
ctx = canvas.getContext("2d");
canvas.width = window.innerWidth; // todo: update on resize
canvas.height = window.innerHeight;
ctx.font = "14px monospace"; // use same font in canvas as for pre
ctx.strokeStyle = "#d00";
ctx.translate(0.5, 0.5); // makes lines sharper for demo
window.onscroll = drawBoxes; // we need to track scrolling
drawBoxes();
function drawBoxes() { // render line boxes (y)
ctx.clearRect(0, 0, canvas.width, canvas.height);
for(var i = 0; i < count; i++) {
var w = ctx.measureText(lines[i]).width;
if (w) ctx.strokeRect(rect.left, rect.top + i * lineH - window.scrollY, w, lineH - 1);
showChars(lines[i], rect.top + i * lineH - window.scrollY, lineH);
}
}
function showChars(line, y, h) { // render char lines (x)
ctx.beginPath();
for(var i = 0, ch, x, s = ""; ch = line[i]; i++) {
s += ch;
x = ctx.measureText(s).width;
ctx.moveTo(x, y); ctx.lineTo(x, y + h - 1);
}
ctx.globalAlpha = 0.2;
ctx.stroke();
ctx.globalAlpha = 1;
}
canvas {position:fixed;left:0;top:0;z-index:-1}
pre {font:14px monospace}
<canvas></canvas>
<pre>//COBLPGM EXEC PGM=COBLPGM
//INPUT DD DSN=SORT,DISP=(OLD,DELETE)
//NACHA DD DSN=NODE.OPER.COBLPGM.OUT(+1)
//SORT2 EXEC PGM=SORT
//SORTIN DD DSN=NODE.OPER.COBLPGM.OUT(+1)
//SORTOUT DD DSN=SORT2,DISP=(,PASS)
//SYSIN DD DSN=NODE.OPER.PROCLIB(MEM)
//UNRELATE EXEC PGM=UNPGM
//INPUT DD DSN=NODE.OPER.UNRELATED.FILE
//REPORT DD DSN=REPORT
//TSTEMPT1 EXEC PGM=SPOPNCLO
//IN DD DSN=SORT2,DISP=(OLD,DELETE)
// IF TSTEMPT1.RC=0 THEN
//SORT3 EXEC PGM=SORT
//SORTIN DD DSN=NODE.OPER.COBLPGM.OUT(+1)
//SORTOUT DD DSN=SORT3,DISP=(,PASS),LRECL=141
//SYSIN DD DSN=NODE.OPER.CNTRLCDS(PARM)
// ENDIF</pre>

Loop an image in Flash

I want to have a scene where an image which is 5000 pixels high is moving up 5 pixels each frame-refresh. When the image is all up, I'd like to see the top of the image connected to the bottom of the image. This should be done untill the level is 'done'. How can I 'loop' such an Image?
You can create a copy of that image which you keep hidden/above and the trick is to update the position and loop accordingly so when one image goes bellow the screen it goes back on top and repeats.
Here's a basic snippet to illustrate the idea using the DisplayObject class and the scrollRect property:
//ignore this, you have your content already
var dummyContent:BitmapData = new BitmapData(100,100,false);
dummyContent.perlinNoise(10,10,8,12,true,true);
//important stuff starts here
var container:Sprite = addChild(new Sprite()) as Sprite;//make a container
container.scrollRect = new Rectangle(0,0,dummyContent.width,dummyContent.height);//set a scrollRect/'mask'
var part1:DisplayObject = container.addChild(new Bitmap(dummyContent));//add two copies
var part2:DisplayObject = container.addChild(new Bitmap(dummyContent));//of the same content
part2.y -= part2.height;//set the 2nd at the top of the 1st
addEventListener(Event.ENTER_FRAME,update);
function update(e:Event):void{
//move both
part1.y += 5;
part2.y += 5;
//check if any reach the bottom so they can be moved back up
if(part1.y >= part1.height) part1.y = -part1.height;
if(part2.y >= part2.height) part2.y = -part2.height;
//the above can also be nicely placed in a loop if you plan on using more seamless looping clips/images
}
Obviously you will have different content, but the principle is the same.
If you're working with images, you can simply use BitmapData's copyPixels method:
var s:int = 5;//scroll speed
//make some content
var w:int = 100;
var h:int = 100;
var dummyContent:BitmapData = new BitmapData(w,h,false);
dummyContent.perlinNoise(10,10,8,12,true,true);
//prepare for stiching
var renderPos:Point = new Point();//position to render the current image to
var prenderPos:Point = new Point();//position to render the previous image (the 'hidden' copy above)
var render:BitmapData = new BitmapData(w,h,false);//create a bitmap data instance to render updated pixels int
addChild(new Bitmap(render));//and add it to the stage
addEventListener(Event.ENTER_FRAME,update);
function update(e:Event):void{
renderPos.y = (renderPos.y+s)%h;//update the scroll position for the 1st part, % is used to loop back to 0 when the position gets to the content height
prenderPos.y = renderPos.y - h;//update the scroll position for the 2nd part (above)
render.lock();//freeze pixel updates
render.copyPixels(dummyContent,dummyContent.rect,renderPos);//copy pixels from the scroll position to the bottom
render.copyPixels(dummyContent,dummyContent.rect,prenderPos);//copy pixels from the top to the scroll position
render.unlock();//unfreeze/update ALL THE PIXELS
}
You can try to use a Rectangle object which changes height (height-scrollPosition) so you potentially access less pixels each time or you can manually work out single for loops using BitmapData's getVector method, but that's something to look into if performance is actually an issue for such a simple task and it's worth checking what's faster ( copy full bitmap rect vs copy partial bitmap rect vs manually copy values using vector )
Be warned, Flash cannot load an image greater than 16,769,025 pixels (or 4095x4095). The height of 5000 pixels will work as long as the width is not greater than 3353.
That said, I'd loop the image by keeping two copies of the image onstage, move both at the same time with a parent object, and reset to origin once your loop point is met.
Consider the following stage setup:
Stage ¬
0: MainTimeline:MovieClip ¬
0: Container:MovieClip ¬
0: img1:Bitmap
1: img2:Bitmap
Now moving container up, you'd just need to check that the looping second image reaches the origin point of the first image.
function onEnterFrame(e:Event):void {
Container.y = Container.y - 5;
if (Container.y < -5000) {
Container.y = -5;
}
}

actionscript 3 position textfield N pixels from bottom or 90% from top

I'm new to actionscript 3. I want to create a textfield that is either N number of pixels from the bottom of the stage or 90% from the top of the stage.
Basically i want the textfield to always appear near the bottom of the stage. What property of the TextField() object do I configure to achieve this?
function updateTextPosition():void
{
var newPositionY:Number = (stage.stageHeight * .90);
myTextField.y = newPositionY;
}
Now if you want to account for the height of the actual text for whatever reason, you change it to this:
function updateTextPosition():void
{
var newPositionY:Number = (stage.stageHeight * .90) - myTextField.textHeight;
myTextField.y = newPositionY;
}
Remember the origin of the field is top left, so the bottom of the text will appear at myTextField.x + myTextField.textHeight;.
Also, you can listen for the RESIZE event on the stage and update your TextField like so:
stage.addEventListener(Event.RESIZE, onStageResized);
function onStageResized(e:Event):void
{
updateTextPosition();
}