Character boundaries of text field based on parent - actionscript-3

I have a text field inside a container. I'm wondering is it possible to find the boundaries of each character based on the container and not the text field.
Here is a sample screen shot:
And normal state would be like this:
With this I can find the bounds of each character based on text field, But I need it based on the container:
var rect:Rectangle = new Rectangle();
for (var i:int = 0; i < textField.length; i++){
rect = textField.getCharBoundaries(i);
}
Is there anybody whom has an experience on this?

I believe you have to make use of Point conversions.
var rect:Rectangle = new Rectangle();
for (var i:int = 0; i < textField.length; i++){
rect = textField.getCharBoundaries(i);
var globalTopLeft:Point = textField.localToGlobal(rect.topLeft);
var globalBottomRight:Point = textField.localToGlobal(rect.bottomRight);
var containerTopLeft:Point = container.globalToLocal(globalTopLeft);
var containerBottomRight:Point = container.globalToLocal(globalBottomRight);
rect = new Rectangle(containerTopLeft.x,containerTopLeft.y,containerBottomRight.x-containerTopLeft.x,containerBottomRight.y-containerTopLeft.y)
}

If the TextField is a child of the container and the TextField is not scaled, you can just do:
rect = textField.getCharBoundaries(i);
rect.x += textField.parent.x;
rect.y += textField.parent.y;

Related

My bar charts overlap eachother. Need help to solve it

im making a code where I have an input field and a button on my screen. In the code below btnLeggTil (its norwegian) adds the number you wrote in the input field. It determines the height of the bars. My code is supposed to let the user add bars of whatever the height he/she prefers. As you can see I have put alot of my code inside a loop. The problem with the code is that the bars it makes, overlap eachother. I need to have a space between each bar, but don't know how. Thanks in advance! You can test out the code yourself and see (just remember to make a button and input field with names btnLeggTil and txtInn.
("høyde" means height) ("bredde" means width) ("verdier" means values) sorry its all norwegian
var verdier:Array = new Array();
btnLeggTil.addEventListener(MouseEvent.CLICK, leggtil);
function leggtil (evt:MouseEvent)
{
verdier.push(txtInn.text);
var totHøyde:int = 200; //total height on diagram
var totBredde:int = 450; //total width on diagram
var antall:int = verdier.length;
var xv:int = 50;
var yb:int = 350;
var bredde:int = (totBredde/antall) * 0.8;
var mellom:int = (totBredde/antall) * 0.2;
var maksHøyde:int = maksVerdi(verdier);
function maksVerdi(arr:Array):Number //finds the biggest value in the array
{
//copies to not destroy the order in the original
var arrKopi:Array = arr.slice();
arrKopi.sort(Array.NUMERIC|Array.DESCENDING);
return arrKopi[0];
}
for(var i:int = 0; i < verdier.length; i++)
{
graphics.lineStyle(2, 0x000000);
graphics.beginFill(0x00ff00);
graphics.drawRect(xv + (bredde+mellom)*i, yb, bredde, -verdier[i] * (totHøyde/maksHøyde));
graphics.endFill();
var txtTall = new TextField();
txtTall.x = xv + (bredde+mellom)*i + 5;
txtTall.y = yb - verdier[i] - 10;
txtTall.type = "dynamic";
txtTall.text = verdier[i];
addChild(txtTall);
}
}
You need to modify your for loop a bit,
graphics.clear();
graphics.lineStyle(2, 0x000000);
graphics.beginFill(0x00ff00);
for(var i:int = 0; i < verdier.length; i++)
{
graphics.drawRect(xv + (bredde+mellom)*i, yb, bredde, -verdier[i] * (totHøyde/maksHøyde));
var txtTall = new TextField();
txtTall.x = xv + (bredde+mellom)*i + 5;
txtTall.y = yb - verdier[i] - 10;
txtTall.type = "dynamic";
txtTall.text = verdier[i];
addChild(txtTall);
}
graphics.endFill();

Can you create new sprite out of two or more already existing by taking their overlapping part

I have two spites created by drawPath(). Sometimes they might overlap each other and when it happens i want to create new sprite, which contains only overlapping part. Maybe it is really simple but i couldn't find any solution exept draw a rectangle of zone where they overlaps. So if it could be done i really appreciate your help.
for (var j:int = 0; j < zonesAmount; j++) {
var sp:Sprite = new Sprite();
var zoneCoord:Vector.<Number> = new Vector.<Number>(0, false);
var zoneCommands:Vector.<int> = new Vector.<int>(0, false);
var o:XML;
for each (o in xml.ZONE[j].POINT)
{
var tmpCoord:int = o.#X;
zoneCoord.push(tmpCoord);
tmpCoord = o.#Y;
zoneCoord.push(tmpCoord);
}
zoneCommands.push(GraphicsPathCommand.MOVE_TO);
for (var i:int = 0; i < (zoneCoord.length - 2)/4; i++)
zoneCommands.push(GraphicsPathCommand.CURVE_TO);
sp.graphics.beginFill(xml.ZONE[j].#COLOR);
sp.graphics.drawPath(zoneCommands, zoneCoord);
sp.graphics.endFill();
sp.alpha = 0.1;
zones[xml.ZONE[j].#ID - 1] = sp;
var picsToolt:mapTooltip = new mapTooltip(15, 15, xml.ZONE[j].SOURCE.#NMB, xml.ZONE[j].SOURCE.#SRC);
picsToolt.Register(zones[xml.ZONE[j].#ID - 1], "");
addChild(zones[xml.ZONE[j].#ID - 1]);
}
Don't bother for addChild(zones[xml.ZONE[j].#ID - 1]) it doesn't matter
Here is examples of what i'm trying to do:
first and second
Second one describes exactly in what i'm intrested, red rect is what i can do and blue line is what i want

Positioning of Dynamically attached library objects in ActionScript 3.0

I am re-learning ActionScript, and I am trying to learn from
digitaldogbyte.com 'Dynamically attached library objects in ActionScript 3.0'. This example, in digialdogbyte, sets the position of each MovieClip across the X position. At high number of numberOfClips, the Objects run right and of the Stage, and out-of-view.
I am trying to adapt the following script to:
wrap the flow of objects to a new line when the edge of the Stage is reached
every other block is coloured red with text colour set to white
The ActionScript:
var numberOfClips:Number = 150;
var xStart:Number = 0;
var yStart:Number = 0;
var xVal:Number = xStart;
var xOffset:Number = 2;
for (var i:Number=0; i<numberOfClips; i++)
{
var mc:myClip = new myClip();
mc.name = "myClip"+(i+1);
this.addChild (mc);
mc.y = yStart;
mc.x = xVal;
xVal = mc.x + mc.width + this.xOffset;
mc.label_txt.text = (i).toString();
}
I'd be grateful if anyone could suggest ways to adapt this script as such.
Add something simple like:
var numberOfClips:Number = 150;
var grid:Rectangle = new Rectangle(0, 0, 20, 20);
for(var i:Number = 0; i < numberOfClips; i++)
{
var mc:myClip = new myClip();
addChild(mc);
mc.x = grid.x;
mc.y = grid.y;
grid.x += grid.width;
// If the new x position is outside of the stage, reset it and
// increase the y position.
if(grid.x + grid.width > stage.stageWidth)
{
grid.x = 0;
grid.y += grid.height;
}
}
You can adjust the width and height of the grid on line 2.

AS3: Random Point on Irregular Shape

I have a MovieClip holding an irregular shape such as this one:
I need to generate a random point on this shape.
I can use brute force by generating points within the bounding box and then hitTesting to see if they reside on the irregular shape. However, I'm sure there's a more efficient way to tackle this problem.
What is the most efficient way to generate a random point on an irregular shape?
You mentioned hitTest, but I assume you meant hitTestPoint().
If so, a function go get the random points you mention, would look a bit like this:
function getRandomPointsInClip(target:MovieClip,numPoints:int):Vector.<Point>{
var points:Vector.<Point> = new Vector.<Point>(numPoints,true);
var width:Number = target.width,height:Number = target.height;
for(var i:int = 0; i < numPoints ; i++){
var point:Point = new Point(target.x+Math.random() * width,target.y+Math.random() * height);
if(target.hitTestPoint(point.x,point.y,true)) points[i] = point;//is the random coord inside ?
else i = i-1;//nope, go back one step - > retry above until it is inside
}
return points;
}
The other I hinted at in my comment involves looping through non transparent pixels in a bitmap data of your object. This method would insure you don't have many duplicates, as opposed to the previous method, but it also means, you have less control over the number of points created and there's extra memory used for creating the bitmap. Still, for documentation purposes, here is the function:
function getGridPointsInClip(target:MovieClip,res:int,offset:Number = 3):Vector.<Point>{
var points:Vector.<Point> = new Vector.<Point>();
var x:int,y:int,alpha:int,w:int = int(target.width),h:int = int(target.height);
var bmd:BitmapData = new BitmapData(w,h,true,0x00FFFFFF);bmd.draw(target);
var pixels:Vector.<uint> = bmd.getVector(bmd.rect),numPixels:int = w*h;
for(var i:int = 0; i < numPixels; i+=res) {
x = i%bmd.width;
y = int(i/bmd.width);
alpha = pixels[i] >>> 24;
if(alpha > 0) points.push(new Point(x+random(-offset,offset),y+random(-offset,offset)));
}
return points;
}
function random(from:Number,to:Number):Number {
if (from >= to) return from;
var diff:Number = to - from;
return (Math.random()*diff) + from;
}
And here'a very basic test:
var pts:Vector.<Point> = getRandomPointsInClip(mc,300);
//var pts:Vector.<Point> = getGridPointsInClip(mc,100,4);
for(var i:int = 0 ; i < pts.length; i++) drawCircle(pts[i].x,pts[i].y,3,0x009900);
function getRandomPointsInClip(target:MovieClip,numPoints:int):Vector.<Point>{
var points:Vector.<Point> = new Vector.<Point>(numPoints,true);
var width:Number = target.width,height:Number = target.height;
for(var i:int = 0; i < numPoints ; i++){
var point:Point = new Point(target.x+Math.random() * width,target.y+Math.random() * height);
if(target.hitTestPoint(point.x,point.y,true)) points[i] = point;//is the random coord inside ?
else i = i-1;//nope, go back one step - > retry above until it is inside
}
return points;
}
function getGridPointsInClip(target:MovieClip,res:int,offset:Number = 3):Vector.<Point>{
var points:Vector.<Point> = new Vector.<Point>();
var x:int,y:int,alpha:int,w:int = int(target.width),h:int = int(target.height);
var bmd:BitmapData = new BitmapData(w,h,true,0x00FFFFFF);bmd.draw(target);
var pixels:Vector.<uint> = bmd.getVector(bmd.rect),numPixels:int = w*h;
for(var i:int = 0; i < numPixels; i+=res) {
x = i%bmd.width;
y = int(i/bmd.width);
alpha = pixels[i] >>> 24;
if(alpha > 0) points.push(new Point(x+random(-offset,offset),y+random(-offset,offset)));
}
return points;
}
function random(from:Number,to:Number):Number {
if (from >= to) return from;
var diff:Number = to - from;
return (Math.random()*diff) + from;
}
function drawCircle(x:Number,y:Number,radius:Number,color:uint):void{
graphics.lineStyle(1,color);
graphics.drawCircle(x-radius,y-radius,radius);
}
HTH
If you think of some non-blob like shapes, it's clear the check random pixel, try again method isn't really a good way. The bounding box area could be huge compared to the shape area.
What you could do to improve the effectiveness is getting a vector of the BitmapData of the shape. It should contain all pixels of the bounding box. Update - it would be nice now if we could pick a random point, and remove it from the vector if it isn't inside the shape. Unfortunately the vector only contains the pixels' colour, not the position which is implicit and only correct if we don't change the vector's length. Since we don't need to know the actual colour, we can omit all transparent pixels and store an inside pixel's position as it's value in the vector. This way we don't need to create a new object for each pixel of the shape (that would be quite expensive!).
var v:Vector.<uint> shapeBoxBitmap.getVector(shapeBoxBitmap.rect);
var pixelNum:int = v.length;
for(var i:uint = 0; i < pixelNum; i++) {
if( v[i] && 0xFF000000 == 0) { // transparent pixel, outside off shape
v.splice(i,1);
} else {
v[i] = i;
}
}
//get random point
var randomPixel:int = v[Math.floor(Math.random()*v.length)];
var point:Point = new Point(randomPixel%shapeBitmap.width,int(randomPixel/shapeBitmap.width));

How to modify position of children inside loop in AS3

I'm trying to make a dynamic image gallery from and xml. From my tutorials, right now i've got it so it will constantly add the next thumbnail below the other, which is fine, but I'm trying to figure out how to make it that once it reaches a certain y coordinate, it will move the x coordinate over and stack them again. So that rather one long list of thumbs, it will be a side by side stack. For some reason, I can't get it in my head how something like this would work. My goal is to have a side by side stack that I will end up putting in a movie clip that will be masked to show only 2 stacks at a time. Then when clicking a button will slide it over. I was planning to use the "movieclip.length" to calculate how far over to move it, but i haven't gotten that far yet. This is what I got:
var gallery_xml:XML;
var xmlReq:URLRequest = new URLRequest("xml/content.xml");
var xmlLoader:URLLoader = new URLLoader();
var imageLoader:Loader;
function xmlLoaded(event:Event):void
{
gallery_xml = new XML(xmlLoader.data);
info_txt.text = gallery_xml.screenshots.image[0].attribute("thumb");
for(var i:int = 0; i < gallery_xml.screenshots.image.length(); i++)
{
imageLoader = new Loader();
imageLoader.load(new URLRequest(gallery_xml.screenshots.image[i].attribute("thumb")));
imageLoader.x = 0;
imageLoader.y = i * 70 + 25;
imageLoader.name = gallery_xml.screenshots.image[i].attribute("src");
addChild(imageLoader);
imageLoader.addEventListener(MouseEvent.CLICK, showPicture);
}
}
xmlLoader.load(xmlReq);
xmlLoader.addEventListener(Event.COMPLETE, xmlLoaded);
function showPicture(event:MouseEvent):void
{
imageLoader = new Loader();
imageLoader.load(new URLRequest(event.target.name));
imageLoader.x = 200;
imageLoader.y = 25;
addChild(imageLoader);
}
I can't seem to wrap my head around what I can do to move things over dynamically without having to write a custom if for each set of positions.. I get the feeling I've totally forgotten how to do algebra.
I'd suggest one of the following two solutions (untested):
var next_x:Number = 0.0;
var next_y:Number = 25.0;
for (var i:int = 0; i < gallery_xml.screenshots.image.length(); ++i)
{
// ...
imageLoader.y = next_y;
imageLoader.x = next_x;
next_y += 70;
if (next_y > THRESHOLD)
{
next_x += X_OFFSET;
next_y = 25.0;
}
}
That is, just keep track of where your next image will be placed and adjust that coordinate accordingly when you exceed thresholds. If you want to use your i variable, you'll have to calculate what row and column the image will be placed at:
for (var i:int = 0; i < gallery_xml.screenshots.image.length(); ++i)
{
// ...
var row:int = i % MAX_ITEMS_PER_COLUMN;
var column:int = i / MAX_ITEMS_PER_COLUMN;
imageLoader.y = 25 + row * 70;
imageLoader.x = column * COLUMN_WIDTH;
}