I'm trying to recreate some flash shapes that appear on rollover upon a circle symbol. I'm needing to convert flash x and y points to the canvas coordinate grid. I figured out how to convert the circle coord points. However, the info I'm given for the shapes that appear on rollover make no sense to me.
For example, take this rollover point, where the dimensions refer to the registration point (little cross in the upper left):
x = 532.30
y = 30.35
w/h = 19.80
But based off this, the info I get for the rectangle that appears on rollover makes no sense:
x = -7.30
y = 17.30
w = 29.0
h = 16.5
I figured this meant that the rectangle's upper left point was 7.30 pixels to the left, and 17.30 pixels down from the registration point of the circle. Is that right? What origin are these x and y coordinates based off of?
The width and height are completely confusing to me though. The given width is 29.0, but this can't be right. If I get x and y coordinates just using my cursor, its clear that the rectangle is much wider than this:
564 - 521 = 43
43 != 29
Please help me understand the mysterious info box I'm being presented with for this rectangle. I just need to get some vanilla coordinates for it so I can draw it on the HTML5 canvas.
What origin are these x and y coordinates based off of?
These x and y coordinates are based off of the registration point of tab button.
43 != 29
When you work with symbols on a stage, the symbols that you're working with aren't the actual original Library symbol. They're copies that can be manipulated by scaling them, applying color and opacity effects and...
This instance of tab button is scaled, if you open library panel and edit tab symbol you can see the actual size.
UPDATE
after I change width and height of tab button to 19.80:
29*(150/100)=43.5
Related
In the attached Google charts Pie chart the labels fit well inside the segments. Determining the length of a bit of text in HTML5 canvas is easy enough - but how do you determine whether the label will fit into a particular segment (using trigonometry) ? As you can see on the image, two of the segments don't have labels inside the segment.
EDIT: Here's an example of what I have at the moment: https://www.rgraph.net/tests/canvas.pie/in-pie-labels.html
As you see the labels for the small segments overlap. What I'm after is a way to calculate whether there's enough space for the labels at the point where they're going to be rendered. If not, I can just not draw the label like in the example image above.
Could chord size be useful to do this?
Here's the forumulae for the chord size that I found via Google:
"Chord length using trigonometry = 2 × r × sin(θ/2); where 'r' is the radius of the circle and 'θ' is the angle subtended at the center by the chord."
I sorted it (in about one hour) after 3 days of trying to calculate it with trig by using the built-in context.isPointInPath() function...
Draw the text (transparent color) to get the coordinates (x/y/w/h) of it. You might be able to get away with measuring it to get the width and height.
Draw the segment in a transparent color and do not stroke or fill it. Also, do not close the path.
Test each corner of the text rectangle (formed the x/y/w/h that you got above) using the context.isPointInPath() function. If the function returns true for each corner of the rectangle formed by the coordinates of the text, then the text will fit into the segment.
Using the first photo below, let's say:
The red outline is the stage bounds
The gray box is a Sprite on the stage.
The green box is a child of the gray box and has a rotation set.
both display object are anchored at the top-left corner (0,0).
I'd like to rotate, scale, and position the gray box, so the green box fills the stage bounds (the green box and stage have the same aspect ratio).
I can negate the rotation easily enough
parent.rotation = -child.rotation
But the scale and position are proving tricky (because of the rotation). I could use some assistance with the Math involved to calculate the scale and position.
This is what I had tried but didn't produce the results I expected:
gray.scaleX = stage.stageWidth / green.width;
gray.scaleY = gray.scaleX;
gray.x = -green.x;
gray.y = -green.y;
gray.rotation = -green.rotation;
I'm not terribly experienced with Transformation matrices but assume I will need to go that route.
Here is an .fla sample what I'm working with:
SampleFile
You can use this answer: https://stackoverflow.com/a/15789937/1627055 to get some basics. First, you are in need to rotate around the top left corner of the green rectangle, so you use green.x and green.y as center point coordinates. But in between you also need to scale the gray rectangle so that the green rectangle's dimensions get equal to stage. With uniform scaling you don't have to worry about distortion, because if a gray rectangle is scaled uniformly, then a green rectangle will remain a rectangle. If the green rectangle's aspect ratio will be different than what you want it to be, you'd better scale the green rectangle prior to performing this trick. So, you need to first transpose the matrix to offset the center point, then you need to add rotation and scale, then you need to transpose it away. Try this set of code:
var green:Sprite; // your green rect. The code is executed within gray rect
var gr:Number=green.rotation*Math.PI/180; // radians
var gs:Number=stage.stageWidth/green.width; // get scale ratio
var alreadyTurned:Boolean; // if we have already applied the rotation+scale
function turn():void {
if (alreadyTurned) return;
var mat:flash.geom.Matrix=this.transform.matrix;
mat.scale(gs,gs);
mat.translate(-gs*green.x,-gs*green.y);
mat.rotate(-1*gr);
this.transform.matrix=mat;
alreadyTurned=true;
}
Sorry, didn't have time to test, so errors might exist. If yes, try swapping scale, translate and rotate, you pretty much need this set of operations to make it work.
For posterity, here is what I ended up using. I create a sprite/movieClip inside the child (green) box and gave it an instance name of "innerObj" (making it the actually content).
var tmpRectangle:Rectangle = new Rectangle(greenChild.x, greenChild.y, greenChild.innerObj.width * greenChild.scaleX, greenChild.innerObj.height * greenChild.scaleY);
//temporary reset
grayParent.transform.matrix = new Matrix();
var gs:Number=stage.stageHeight/(tmpRectangle.height); // get scale ratio
var mat:Matrix=grayParent.transform.matrix;
mat.scale(gs,gs);
mat.translate(-gs * tmpRectangle.x, -gs * tmpRectangle.y);
mat.rotate( -greenChild.rotation * Math.PI / 180);
grayParent.transform.matrix = mat;
If the registration point of the green box is at one of it's corners (let's say top left), and in order to be displayed this way it has a rotation increased, then the solution is very simple: apply this rotation with negative sign to the parent (if it's 56, add -56 to parent's). This way the child will be with rotation 0 and parent -> -56;
But if there is no rotation applied to the green box, there is almost no solution to your problem, because of wrong registration point. There is no true way to actually determine if the box is somehow rotated or not. And this is why - imagine you have rotated the green box at 90 degrees, but changed it's registration point and thus it has no property for rotation. How could the script understand that this is not it's normal position, but it's flipped? Even if you get the bounds, you will see that it's a regular rectangle, but nobody know which side is it's regular positioned one.
So the short answer is - make the registration point properly, and use rotation in order to display it like in the first image. Then add negative rotation to the parent, and its all good :)
Edit:
I'm uploading an image so I can explain my idea better:
As you can see, I've created a green object inside the grey one, and the graphics INSIDE are rotated. The green object itself, has rotation of 0, and origin point - top left.
#Vesper - I don't think that the matrix will fix anything in this situation (remember that the green object has rotation of 0).
Otherwise I agree, that the matrix will do a pretty job, but there are many ways to do it :)
Please this fiddle I have copied my complete project in it
here if you open the fiddle in the output you can see an image, scribble on the image selecting pen,add text etc(like this perform some functions).then rotate the group using rotate button and then try to scribble you will understand what is the problem exactly.
In me view Problem is I am having a stage and a layer is added to the stage and a group is added to the layer and different elements like lines text etc are added to the group. then group is rotated the i am trying to draw the line based on the mouse position of the stage.But it is not coming correctly because the group got rotated the x and y what we are taking to draw a line is from stage.I need to take the x and y from the group not from the stage is their any way.If hav't understand please ask me or post a reply.
This should get you fairly close: http://jsfiddle.net/k4qB8/24/
// This rotates that added active line along with your group.
// This makes the draw direction correct
activeline.setRotationDeg(0-rootGroup.getRotationDeg());
// Here you'll have to figure a way to calculate how much to move the
// line over so the draw is on the correct spot
// This is as close as I got it
if(Math.abs(rootGroup.getRotationDeg()%360)==0)
activeline.move(rootGroup.getX()-375, rootGroup.getY()-175);
if(Math.abs(rootGroup.getRotationDeg()%360)==90)
activeline.move(rootGroup.getX()-175, rootGroup.getY()+375);
if(Math.abs(rootGroup.getRotationDeg()%360)==180)
activeline.move(rootGroup.getX()+375, rootGroup.getY()+175);
if(Math.abs(rootGroup.getRotationDeg()%360)==270)
activeline.move(rootGroup.getX()+175, rootGroup.getY()-375);
Also, add some more logic for counter-clockwise rotation, as this doesn't work 100%.
I think the real solution would be to just draw on separate layers for each rotation, kind of like this:
if (rotation is 90) : draw on lineLayer1;
if (rotation is 180) : draw on lineLayer2;
if (rotation is 270) : draw on lineLayer3;
if (rotation is 360 || 0) : draw on lineLayer4;
This way you could just rotate the layers which are not drawn on to simulate the feel of rotation.
I'm currently struggling on a problem that seems far beyond my maths capacities (been a long time since I've made some proper maths...) and I would appreciate some help on that.
Here's my setting :
I got some simple shapes (rectangles), and I "project" their bottom points on a line, coming from an Origin point.
Up to this point everything is fine.
But now I'd like to draw the original shape distorted as if it was projected with some perspective on a plane.
Please consider that I have nothing related to any rotation, isometric or any 3D or fake 2D perspective in my code, I'm only trying to draw some shapes using the graphics library to only have a feeling of something real.
Here's a quick drawing of what I'm trying to do :
What I know :
Origin point coordinates
the rect position & sizes
the red line position
the A & B points coordinates
What I want to determine is the coordinates of the C & D points, thing that could be easy if I wasn't struggling to find the "Origin bis" coordinates.
What I'm trying to do is to fake the projection of my rectangle on something that can be considered as a "floor" (related to the plane where my original rectangle is that can be seen as a wall).
Maybe I'm over-complicating the problem or maybe I fail to see any other easier way to do it, but I'm really not good anymore in any geometry or maths thing... :-(
Thanks a lot for your answers !
hmm i don't know if I undestood it correctly but I think you have too few input parameters:
you said the following information is given:
Origin point coordinates
the rect position & sizes
the red line position
the A & B points coordinates
I don't think it is possible to get your projected rectangle with this information alone.
Additionally, I think your green lines and the 'origin Bis' aren't helpful as well.
Perhaps, try this:
Supose, a blue line going through the points C & D is given as well.
Then you could find your projected rectangle by projecting the top of the rectangle onto that blue line.
So in summary:
You define an origin + two parallel lines, a red and a blue one.
Then you can project the top of the rect onto the blue line and the bottom of the rect onto the red line, yielding the points A,B,C,D
I hope this helps.
If I'm right, this code will show what you wanted to see.
First of all, I've ignored your initial setup of objects and information, and focused on the example situation itself; fake-projecting shadow for a "monolith" (any object is possible with the example below, even textured)
My reason was that it's really quite easy with the Matrix class of ActionScript, a handy tool worth learning.
Solution:
You can use the built-in Matrix class to do skew transform on DisplayObjects.
Try this example:
(The "useful" part lies in the _EF EnterFrame handler ;) )
import flash.display.MovieClip;
import flash.geom.Matrix;
import flash.events.Event;
import flash.display.BitmapData;
const PIP180:Number = Math.PI / 180;
const MAX_SHADOW_HEIGHT_MULTIPLIER:Number = 0.25; // you can also calculate this from an angle, like ... = Math.sin(angle * PIP180);
const ANIM_DEG_PER_FRAME:Number = 1.0 * PIP180; // the shadow creeps at a +1 degree per frame rate
var tx:BitmapData = new MonolithTexture(); // define this BitmapData in the library
var skew:Number = -10 * PIP180; // initial
var mono:MovieClip = new MovieClip();
mono.graphics.beginBitmapFill(tx);
// drawn that way the registration point is 0,0, so it's standing on the ground
mono.graphics.drawRect(0, -tx.height, tx.width, tx.height);
mono.graphics.endFill();
// align monolith to the "ground"
mono.x = stage.stageWidth / 2;
mono.y = stage.stageHeight - 100;
// make it be 100x300 pixel
mono.width = 100;
mono.height = 300;
var shad:MovieClip = new MovieClip();
// colored:
shad.graphics.beginFill(0x000000);
// or textured:
//shad.graphics.beginBitmapFill(tx);
shad.graphics.drawRect(0, -tx.height, tx.width, tx.height);
shad.graphics.endFill();
addChild(shad); // shadow first
addChild(mono); // then the caster object
addEventListener(Event.ENTER_FRAME, _EF);
function _EF(e:Event):void {
// animate skew on the positive half circle
skew = (skew + ANIM_DEG_PER_FRAME) % Math.PI;
// Matrix takes 6 parameters: a, b, c, d, x, y
// for this shadow trick, use them as follows:
// a = width scaling (as mono and shad are drawn in the same way, copy mono.scaleX for a perfect fit
// b = 0, because we don't want to project the vertical axis of transformation to the horizontal
// c = horizontal skew
// d = height scaling * skew * making it a bit flat using the constant
// x = mono.x, ...
// y = mono.y since originally mono and shad look alike, only the Matrix makes shad render differently
var mtx:Matrix = new Matrix(mono.scaleX, 0, Math.cos(skew), mono.scaleY * Math.sin(skew) * MAX_SHADOW_HEIGHT_MULTIPLIER, mono.x, mono.y);
shad.transform.matrix = mtx;
}
Now all you got to know to utilize this in your case, is the following N factors:
Q1: from what angle you want to project the shadow?
A1: horizontal factor is the skew variable itself, while vertical angle is stored as constant here, called MAX_SHADOW_HEIGHT_MULTIPLIER
Q2: do you want to project shadow only "upwards", or freely?
A2: if "upwards" is fine, keep skew in the positive range, otherwise let it take negative values as well for a "downward" shadow
P.S.: if you render the internals of the objects that they don't snap to 0 y as a base point, you can make them seem float/sink, or offset both objects vertically with a predefined value, with the opposite sign.
You face 1 very simple problem, as you said:
'What I want to determine is the coordinates of the C & D points, thing that could be easy if I wasn't struggling to find the "Origin bis" coordinates.'
But these co-ordinates relate to each other, so without one (or another value such as an angle) you cannot have the other. If you are to try this in 3D you are simply allowing the 3D engine to define 'Origin bis' and do your calculating for C and D itself.
So regardless you will need an 'Original bis', another value relating to the redline or your Rect for which to calculate the placement of C and D.
I remember making stuff like this and sometimes it's better to just stick with simple, you either make an 'Original bis' defines by yourself (it can be either stationary or move with the player/background) and get C and D the way you got A and B only that you use a lower line than the red line, or as I would of done, once you have A and B, simple skew/rotate your projection from those points down a bit further, and you get something the same as an 'Original bis' that follows the player. This works fine at simulating 'feeling of something real' but sadly as has been said, it looking real depends on what you are portraying. We do not know what the areas above or below the red line are (sky/ground, ground/water) and whether 'Origin' and 'Origin bis' is your light source, vanishing point, etc.
In Flash, pixels are calculated using twips, or twentieth of a pixel. Consequently, every position is always in multiples of 0.05. I haven't seen this mentioned in the HTML Canvas spec and am unable to trace the cursor position on Canvas. Does anyone know the accuracy of its pixel calculations?
Edit for clarification:
I'm referring more to Zeno's paradox which says in order to move something from point A to point B, it must first move to a point halfway between the two. And then halfway again, ad infinitum.
So if I want to move on the x axis from point 0 to 100 at 0.5:
At frame 1: 50
Frame 2: 75
Frame 3: 87.5
Then: 93.75, 96.875, 98.4375... etc.
So at what step does the Canvas actually round-up to the next pixel?
I'm unsure what you mean by accuracy of slicing.
Pixels on the Canvas can be drawn to a little less than 0.10, after which they make barely any visible impact.
Of course, if you scale, you can draw things that are 0.00125 pixels, and so on. But they won't be visible if you unscale.
http://jsfiddle.net/GvVD9/
(That first square block on the top-left is a pixel)
Accuracy of the mouse is an entirely different thing, in no way related to the canvas spec.
EDIT:
Well, we can sorta demonstrate that. We can draw a bunch of pixels with y values approaching 100 and see how they compare to a red pixel drawn with the y value 100.
http://jsfiddle.net/GvVD9/46/
Every single horizontally separated piece is just a single 1 by 1 pixel rect using the drawRect command.
50
75
87.5
93.75 // first black pixel you see in image
96.875
98.4375
99.21875
99.609375
99.8046875
99.90234375
99.951171875
99.9755859375
99.98779296875
99.993896484375
99.9969482421875 // last black pixel you see in image