I'm developing a drawing app, and I ran into a problem, and a possible solution would be to be able to resize horizontally (increase or decrease the width) of an image without altering it's pivot, but ending with a "directional resize", it means, that if I start dragging the right resize anchor, the image starts increasing it's width to the right, instead of always taking into consideration the pivot.
So, what I'm doing now is to increase the width and at the same time I move the image width/2, it works, however when I have to rotate the image.. everything starts to get broken, and even if I set the pivot in the middle of the sprite, since the image (that is contained inside the sprite) x is altered, it doesn't matter.
I've read some about matrices, but I'm not sure if this is possible.
Thanks.
There a few ways you can accomplish this. The first is to use a transform matrix.
Here is a function I use to rotate an object around a point in that fashion:
*You'll need to import fl.motion.MatrixTransformer, if not using flashPro you can get it here: https://code.google.com/p/artitem-as3/source/browse/trunk/ArtItem/src/fl/motion/MatrixTransformer.as?r=3
/**
* Rotates a displayObject around the passed local point.
* #param displayObj
* #param relativeDegrees - the relative amount of degrees to rotate the object
* #param point - a local point to rotate the object around, if null, center of bounding box will be used.
*/
public static function rotateAroundPoint(displayObj:DisplayObject, relativeDegrees:Number, point:Point = null):void {
var m:Matrix = displayObj.transform.matrix.clone();
if (!point) {
//default is center of bounding box
var r:Rectangle = displayObj.getBounds(displayObj);
point = new Point(r.x + (r.width * .5), r.y + (r.height * .5));
}
MatrixTransformer.rotateAroundInternalPoint(m, point.x, point.y, relativeDegrees);
displayObj.transform.matrix = m;
}
Another more lazy way to do this, is to use a dummy parent object and just rotate that:
var dummy:Sprite = new Sprite();
dummy.addChild(yourObjectToRotate);
//this effectively makes the anchor point of dummy in the center, so when you rotate it it rotate from the center.
yourObjectToRotate.x = -(yourObjectToRotate.width * .5);
yourObjectToRotate.y = -(yourObjectToRotate.height * .5);
dummy.rotation = 90;
Related
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)
}
I am working on custom product designer which uses Fabric.js. I want to rotate all objects of canvas at once by pressing one button (rotate left, rotate right).
I have achieved this using this code :
stage.forEachObject(function(obj){
obj.setAngle(rotation).setCoords();
});
stage.renderAll();
But it has one bug that every element rotates with its own center point. I want that every element rotates with respect to whole canvas element.
Grouping and rotating the group did not work so well for me. Here is another solution based on this js fiddle.
rotateAllObjects (degrees) {
let canvasCenter = new fabric.Point(canvas.getWidth() / 2, canvas.getHeight() / 2) // center of canvas
let radians = fabric.util.degreesToRadians(degrees)
canvas.getObjects().forEach((obj) => {
let objectOrigin = new fabric.Point(obj.left, obj.top)
let new_loc = fabric.util.rotatePoint(objectOrigin, canvasCenter, radians)
obj.top = new_loc.y
obj.left = new_loc.x
obj.angle += degrees //rotate each object buy the same angle
obj.setCoords()
});
canvas.renderAll()
},
You could add all the objects to a group an then rotate the group. This way you can also set the center for rotation.
This is how it could be solved
function rotate(a) {
var group = new fabric.Group(canvas.getObjects());
//angle is var with scope out of this function,
//so you can use this function as rotate(90) and keep rotating
angle = (angle + a) % 360;
group.rotate(angle);
canvas.centerObject(group);
group.setCoords();
canvas.renderAll();
}
FabricJS rotate everything and maintain the relative position also.
You can download the files here - https://drive.google.com/file/d/1UV1nBdfBk6bg9SztyVoWyLJ4eEZJgZRf/view?usp=sharing
I hope this hasn't been asked too much before. When I search I only get questions pertaining to rescaling to window size.
Now my question. I got one space ship firing a beam against another ship. I want the beam to show for some time and I want it to "bridge" the two ships. In other words, I want the beam to extend its width between the two ships.
I try to do this with a dot movie clip that is 1 pixel wide and high (and aligned left edge). I try to resize it with the following code: (target is the ship to be fire at and owner is the ship firing)
dist.vx = target.x - owner.x;
dist.vy = target.y - owner.y;
dist.dist = Math.sqrt(dist.vx*dist.vx + dist.vy*dist.vy);
width = dist.dist;
x = owner.x;
y = owner.y;
rotation = Math.atan2(target.y-y, target.x-x)*180/Math.PI;
This doesn't work as intended because 1) dot also gets alot bigger in the other dimension - how can I "turn off" this behavior? and 2) sometimes it seems to get way to wide - but only in certain angles...
Any suggestions on either solving the heigh/width scaling or on another way to achieve the same effect?
(I'm new to coding and flash.) Thanks!
By resizing a dot, you will have a rectangle...
You can dynamically create a sprite covering both ships and moveTo the hit point of one ship then lineTo the other ship... You do not need distance calculation at all. What you have to do is being careful on the placement of the sprite. So that you can calculate relative hitting points by simple math.
Suppose you have mc space contining mc ship1 and mc ship2, and hit point coords on ships are named hx, hy and you will use sprite s, calculation will be as follows.
// calculate hit points relative to mc space
var s1HX:int = ship1.x + ship1.hx,
s1HY:int = ship1.y + ship1.hy,
s2HX:int = ship2.x + ship2.hx,
s2HY:int = ship2.y + ship2.hy,
// sprite relative moveTo lineTo coords will be these.
mX: int, mY: int,
lX: int, lY: int;
// top left of sprite will be minimum of the hit coords.
s.x = (s1HX <= s2HX)? s1HX : s2HX;
s.y = (s1HY <= s2HY)? s1HY : s2HY;
// now we can get sprite relative moveTo lineTo coordinates:
mX = s1HX - s.x;
mY = s1HY - s.y;
lX = s2HX - s.x;
lY = s2HY - s.y;
The rest is implementation with using these with fancy line styles etc...
To create a new sprite:
var s:Sprite = new Sprite();
Adding / removing it to/from mc space:
space.addChild(s);
space.removeChild(s);
For graphics use the graphics object of sprite.
s.graphics
For setting line styles you can use:
s.graphics.lineStyle(...) ,
s.graphics.lineBitmapStyle(...),
s.graphics.lineGradientStyle(...)
Functions, please read the manual for usage.
After setting the line style to draw the line use:
s.graphics.moveTo(mX,mY);
s.graphics.lineTo(lX,lY);
For pulsating effects you have to do a little more complicated things such as using tween class which you can read about here: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/fl/transitions/Tween.html
Note that:
Sprites are no complicated magic, they are like mc's but they do not have timelines etc.
Sprites try to scale when width or height change programmatically. So do not touch them, moveTo lineTo automatically sets the size of a sprite...
Scrolling graph. Currently I show a real-time graph by drawing each piece of data as it is generated. To scroll, I simply move the container object left to compensate and erase all the data left of the bounds.
Simple, fast, surprisingly memory efficient...but is there a concern of the coordinates overflowing as I keep adding contents to the right and scrolling the container left? Is there a limit on the x coordinate of an (empty) object? I'm afraid if I keep scrolling the container left indefinitely and writing to ever increasing x coordinates the program would misbehave eventually. Would this occur? If so, at what max coordinates? Or does AS3 handle this automatically?
I did a test, where I keep drawing an item to a container making it bigger and bigger, and moving it to the left. It stopped getting bigger at 105,000,000 pixels. After that the width reported 0 and the x property reported -107,374,182.4 and wouldn't move beyond that.
If you have bitmap data though, the FP10 limit is 8,191 pixels in width or height, and the total number of pixels cannot exceed 16,777,215 pixels.
Here was my code used to test:
var b:Sprite = new Sprite();
addChild(b);
b.x = stage.stageWidth * .5;
var t:Timer = new Timer(100);
t.addEventListener(TimerEvent.TIMER,tick);
t.start();
var moveAmt:Number = 50;
function tick(e:Event):void {
b.x -= moveAmount;
b.graphics.beginFill(Math.random() * 0xFFFFFF);
b.graphics.drawRect(b.width,0,moveAmount,stage.stageHeight);
b.graphics.endFill();
trace(b.width + " : " + b.x);
}
Firstly I'm no expert with Flex so the following might be 101 gotchas.
My first problem is that I'm attempting to rotate a group of objects by 90 degrees that are contained within a canvas, each object is uniform in size containing text and an image. My first problem is that rotating the objects causes them to resize to the bounds of itself. For example if the object is 200 x 250 with an image stretching from 0 to 250 pixels, after rotation the contents would have resized to 200 pixels meaning the image is now 200 pixels. I can subsequently resize the object back up to the appropriate dimensions but feels awkward and clumsy. Is there a better way of performing this rotation where it rotates the object without the being restricted to the bounds of the object?
Secondly, I ideally need this code to run within the creationComplete event. When it does, the positioning / centering of the object is ignore and is different when rendered on the screen (for example, if I run the following code in my click event it rotates perfectly on its center point; through the creationComplete it offsets the object like the center point doesn't exist)?
Any pointers?
My rotation code...
<mx:Script>
<![CDATA[
// Capture the init for the application
private function InitialRotate( e:Event ):void{
var offsetWidth:Number = (this.width / 2);
var offsetHeight:Number = this.y + (this.height / 2);
// Rotates on the center (but resizes)
var tempMatrix:Matrix = this.transform.matrix;
tempMatrix.translate(-offsetWidth,-offsetHeight);
tempMatrix.rotate(90 * (Math.PI / 180));
tempMatrix.translate(+offsetWidth,+offsetHeight);
this.transform.matrix = tempMatrix;
// Adjusts the objects position and width to size appropriately
this.y -= 5.5;
this.width = 256;
}
]]>
</mx:Script>
I uses the rotate property of a spark rect class (recently.spark.primitives.supportClasses.GraphicElement.rotation) and it was as easy as
line.rotation=90;
Maybe this blog is helpful: http://blog.flexexamples.com/2007/09/14/rotating-images-using-the-matrix-class/