I've got two concentric circles with their centers at (centerX,centerY). The inner circle has a radius of 100 and the outer circle has a radius of 400. If take a point on the circumference of the inner circle, I can draw a line from the center to that point. Let's call that point x1,y1). I now want to continue that radius out to the outer concentric circle and calculate the position of that outer point (x2,y2).
I'm adding a 3px 'dot' just to show where x1, y1 is on the screen. (Subquestion: I can't see it...not sure why.)
This is what I'm trying:
var x1:Number = 100;
var y1:Number = 50;
var x2:Number;
var y2:Number;
var centerX:Number = 200;
var centerY:Number = 200;
var myAngle:Number = Math.atan2(y1 - centerY, x1-centerX);
//x2 = x1 + 300 * Math.cos(myAngle);
//y2 = y1 + 300 * Math.sin(myAngle);
x2 = centerX + Math.cos(myAngle) * 400;
y2 = centerY + Math.sin(myAngle) * 400;
trace("x2,y2 = " + x2 + "," + y2);
var myCenterPoint:Sprite = new Sprite();
this.graphics.lineStyle(3,0x00ff00); //green, center point
this.graphics.moveTo(centerX, centerY);
graphics.drawCircle(centerX,centerY,5);
addChild(myCenterPoint);
var myInnerCirclePointMarker:Sprite = new Sprite();
this.graphics.lineStyle(3,0x0000FF); //blue, inner circle circumf. marker
this.graphics.moveTo(x1, y1);
graphics.drawCircle(x1,y1,5);
addChild(myInnerCirclePointMarker);
trace("x2,y2 = " + x2 + "," + y2);
var myOuterCirclePointMarker:Sprite = new Sprite();
this.graphics.lineStyle(3,0xff0000); //red, outer circle circumf. marker
myOuterCirclePointMarker.graphics.drawCircle(x2,y2,5);
addChild(myOuterCirclePointMarker);
this.graphics.moveTo(centerX, centerY);
this.graphics.lineTo(x2, y2); //draw line, which should go through
//x1,y1 and end at x2,y2
I don't think this is going to correctly show me the outer points along all 360 degrees of the circle.
Thanks.
I think you're trig is off here, you shouldn't be multiplying the sin/cos values by 300. You want to draw a line from the centre of circle (centerX, centerY) to x2,y2 (outer circle), but you are using x1,y1 as the centre of your circle. x2,y2 should be calculated from the centre of the circle not from x1,y1 ; Try this
var myAngle:Number = Math.atan2(y1 - centerY, x1 - centerX);
x2 = centerX + Math.cos(myAngle) * 400;
y2 = centerY + Math.sin(myAngle) * 400;
var myCircle:Sprite = new Sprite();
this.graphics.lineStyle(3,0x00ff00);
this.graphics.moveTo(centerX, centerY);
this.graphics.lineTo(x2, y2);
myCircle.graphics.drawCircle(x1,y1,5);
addChild(myCircle);
The reason your x1,y1 circle isn't appearing is because it's not on the inner circle, which has a bounding box of (100,100),(300,300), i.e. (100,50) isn't in the bounding box.
Related
I'm trying to place a text inside my semi circle, graph. I simplified the arc for you context.arc(92.5, 92.5, 72.5, 3.141592653589793, 3.7699111843077517, false); I want to place a value 2 at the end of arc, since the arc represents 20% of overall value.
So far I have tried is
context.translate(centerX, centerY);
context.save();
context.translate(x, y);
context.fillText('2', 0, 3);
context.restore();
I tried to find x and y interception point using (𝑥−ℎ)2+(𝑦−𝑘)2=𝑟2. But I can't place the text at the end of arc. Can some one please help me to solve this? Thank you.
You will need to find the point where the arc ends:
let x = center.x + radius * Math.cos(endArc);
let y = center.y + radius * Math.sin(endArc);
In this case the center of the circle is in the point {x:92.5,y:92.5}, the radius is 72.5. and the end arc is 3.7699111843077517.
I hope this is what you were asking.
const ctx = canvas.getContext("2d");
let cw = canvas.width = 200;
let ch= canvas.height = 200;
ctx.beginPath();
ctx.arc(92.5, 92.5, 72.5, 3.141592653589793, 3.7699111843077517, false);
ctx.stroke();
//find the point where the arc ends
let x = 92.5 + 72.5 * Math.cos(3.7699111843077517);
let y = 92.5 + 72.5 * Math.sin(3.7699111843077517);
// draw the text
ctx.font="12px Arial";
ctx.textAlign="center";
ctx.textBaseline="bottom";
ctx.fillText("2",x,y);
canvas{border:1px solid}
<canvas id="canvas"></canvas>
I have a triangle in canvas and I want to fill it with color .. maybe more than one color .. how I can do that ?
my triangle is here :
function draw() {
var width = 360; // Triangle Width
var height = 400; // Triangle Height
var padding = 90;
// Draw a path
ctx.beginPath();
ctx.moveTo(padding + width/2, padding+height); // Top Corner
ctx.lineTo(padding + width, padding); // TOP Right
ctx.lineTo(padding, padding); // TOP Left
ctx.closePath();
ctx.strokeStyle = "#e8ecef";
ctx.lineWidth = 25;
ctx.stroke();
ctx.restore();
}
the current result is like the one in this image :
the result I want something like this :
please any help ? how I can do this ? or if there is any plugin will help me to do this faster ?
Composition modes
The problem can be solved simply by using a couple of composition modes and very little math (only to calculate correct position).
The receipt would be:
Draw a mask representing the full triangle background (color does not matter as long as it is opaque)
Create a gradient with hard transitions to define different color sections.
Composite a rectangle on top which is clipped to background shape using source-in mode.
Stroke the border using the normal source-over mode
All these steps can reuse a single path. The gradient will allow you to define all colored sections in one place. Just make sure each section starts and end with the same color and that the next section will start from where the previous stopped. This will make a hard edge between the sections.
Since the gradient color stops takes normalized values, it becomes a simple task to match any size simply by defining the gradient line's start and stop points relative to the triangle's position and size.
Adjust as needed.
Example with modified code
I inserted the code in your base code to show where the modifications needs to be.
var ctx = c.getContext("2d"),
width = 360, height = 400, padding = 90, split = 0.33;
// Draw a path that will be reused below
ctx.beginPath();
ctx.moveTo(padding + width/2, padding+height); // Top Corner
ctx.lineTo(padding + width, padding); // TOP Right
ctx.lineTo(padding, padding); // TOP Left
ctx.closePath();
// fill for a mask (color doesn't matter as long as it's opaque)
ctx.fill();
// define gradient
var gr = ctx.createLinearGradient(0, padding, 0, padding+height); // line
gr.addColorStop(0 , "rgb(187, 19, 221)");
gr.addColorStop(split, "rgb(187, 19, 221)");
gr.addColorStop(split, "rgb(38, 199, 222)");
gr.addColorStop(1 , "rgb(38, 199, 222)");
// fill the colored sections (adjust positions as needed)
ctx.globalCompositeOperation = "source-in";
ctx.fillStyle = gr;
ctx.fillRect(0, 0, c.width, c.height);
// stroke outline
ctx.globalCompositeOperation = "source-over";
ctx.strokeStyle = "#e8ecef";
ctx.lineWidth = 25;
ctx.stroke();
<canvas id=c width=500 height=550></canvas>
Effectively, a good way to do this is to draw a base triangle and then a trapezium over the top of this, and then do the stroke over these.
function draw(percent) {
var width = 360; // Triangle Width
var height = 400; // Triangle Height
var padding = 90;
// Draw the purple triangle underneath
ctx.beginPath();
ctx.moveTo(padding + width/2, padding+height); // Top Corner
ctx.lineTo(padding + width, padding); // TOP Right
ctx.lineTo(padding, padding); // TOP Left
ctx.fillStyle = "#990099";
ctx.fill();
// Draw second triangle/trapezium over the top
ctx.beginPath();
ctx.moveTo(padding + width*percent/2, padding+height*percent); //Bottom left
ctx.lineTo(padding + width - width*percent/2, padding+height*percent); //Bottom right
ctx.lineTo(padding + width, padding); // TOP Right
ctx.lineTo(padding, padding); // TOP Left
ctx.fillStyle = "#00ccff";
ctx.fill();
// Draw the grey line around the triangles
ctx.beginPath();
ctx.moveTo(padding + width/2, padding+height); // Top Corner
ctx.lineTo(padding + width, padding); // TOP Right
ctx.lineTo(padding, padding); // TOP Left
ctx.closePath();
ctx.strokeStyle = "#e8ecef";
ctx.lineWidth = 25;
ctx.stroke();
ctx.restore();
}
draw(0.1);
The draw function works with any value between 0 and 1, where 0 is 0% blue and 1 is 100% blue. As this is a triangle, the area filled will not appear equal if at 50%, however the percentage will be halfway between the top and bottom coordinates.
I hope this helps
Triangles and area
To solve for fraction (p) (0-1) to give new height (h1) for a triangle (w) width and (h) height
Area of triangle is
w * h * 0.5
Cutting the triangle will give a triangle and a trapezoid.
We will solve so that the fraction area is the area of the trapezoid.
The area of a trapezoid (the other end to the pointy end) in terms of the triangle w,h and h1 where h1 is the unknown height of the trapezoid.
a1 = w * h1 - (w / 2 * h) * h1 * h1
The h1 * h1 means this solution will be a quadratic so make a formula that equates to 0. We know the area of the trapezoid is the triangle area times the fraction, so use that (w * h * 0.5 * p) and subtract the above area solution in terms of h1 to give
0 = w * h * 0.5 * p - w * h1 - (w / 2 * h) * h12
This gives a quadratic the general form is ax2 + bx + c = 0 (in this case the unknown value x is h1 the height of the trapezoid) which can be solved with (-b (+/-) sqrt(b2 - 4ac) ) / 2a. Because of the (+/-) in the solution there are two answers, at this stage it is unknown which answer is correct.
thus to solve we need a,b,c which are
a = w/(2*h)
b = - w
c = w * h * 0.5 * p
So as a function
// return the height of the trapezoid made from a triangle of width height that
// has an area equal to the area of the triangle * fraction
function getFractionHeightOfTriangle(width,height,fraction){
var a = width / (2 * height);
var b = -width;
var c = width * height * 0.5 * fraction;
// find the two solutions
var h1_a = (-b + Math.sqrt(b * b - 4 * a * c)) / (2 * a);
var h1_b = (-b - Math.sqrt(b * b - 4 * a * c)) / (2 * a);
// from experiment the solution is the second one
// or you can check which is positive and return that
return h1_b;
}
To draw a triangle using the top as the origin
// x,y is the top (pointy end) w is width h is height
// col is stroke colour, col1 is fillColour
// lineW is line width.
var drawTriangle = function(x,y,w,h,col,col1,lineW){
ctx.beginPath();
ctx.strokeStyle = col;
ctx.fillStyle = col1;
ctx.lineWidth = lineW;
ctx.moveTo(x,y );
ctx.lineTo(x + w / 2 ,y + h);
ctx.lineTo(x - w / 2 ,y + h);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
To draw part of a triangle
// See above function for x,y,w,h,col,col1,lineW
// which is == "top" for pointy end and != "top" for trapezoid
// amount is the height of the top
var drawPartTriangle = function(x,y,w,h,which,amount,col,col1,lineW){
ctx.beginPath();
ctx.strokeStyle = col;
ctx.fillStyle = col1;
ctx.lineWidth = lineW;
if(which === "top"){
ctx.moveTo(x,y);
ctx.lineTo(x + w / 2 * (amount / h),y + amount);
ctx.lineTo(x - w / 2 * (amount / h),y + amount);
}else{
ctx.moveTo(x + w / 2 * (amount / h),y + amount);
ctx.lineTo(x + w / 2 ,y + h);
ctx.lineTo(x - w / 2 ,y + h);
ctx.lineTo(x - w / 2 * (amount / h),y + amount);
}
ctx.closePath();
ctx.fill();
ctx.stroke();
}
I'm trying to draw a curve in canvas with a linear gradient stoke style along the curve, as in this image. On that page there is a linked svg file that gives instructions on how to accomplish the effect in svg. Maybe a similar method would be possible in canvas?
A Demo: http://jsfiddle.net/m1erickson/4fX5D/
It's fairly easy to create a gradient that changes along the path:
It's more difficult to create a gradient that changes across the path:
To create a gradient across the path you draw many gradient lines tangent to the path:
If you draw enough tangent lines then the eye sees the curve as a gradient across the path.
Note: Jaggies can occur on the outsides of the path-gradient. That's because the gradient is really made up of hundreds of tangent lines. But you can smooth out the jaggies by drawing a line on either side of the gradient using the appropriate colors (here the anti-jaggy lines are red on the top side and purple on the bottom side).
Here are the steps to creating a gradient across the path:
Plot hundreds of points along the path.
Calculate the angle of the path at those points.
At each point, create a linear gradient and draw a gradient stroked line across the tangent of that point. Yes, you will have to create a new gradient for each point because the linear gradient must match the angle of the line tangent to that point.
To reduce the jaggy effect caused by drawing many individual lines, you can draw a smooth path along the top and bottom side of the gradient path to overwrite the jaggies.
Here is annotated code:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
// canvas related variables
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
// variables defining a cubic bezier curve
var PI2=Math.PI*2;
var s={x:20,y:30};
var c1={x:200,y:40};
var c2={x:40,y:200};
var e={x:270,y:220};
// an array of points plotted along the bezier curve
var points=[];
// we use PI often so put it in a variable
var PI=Math.PI;
// plot 400 points along the curve
// and also calculate the angle of the curve at that point
for(var t=0;t<=100;t+=0.25){
var T=t/100;
// plot a point on the curve
var pos=getCubicBezierXYatT(s,c1,c2,e,T);
// calculate the tangent angle of the curve at that point
var tx = bezierTangent(s.x,c1.x,c2.x,e.x,T);
var ty = bezierTangent(s.y,c1.y,c2.y,e.y,T);
var a = Math.atan2(ty, tx)-PI/2;
// save the x/y position of the point and the tangent angle
// in the points array
points.push({
x:pos.x,
y:pos.y,
angle:a
});
}
// Note: increase the lineWidth if
// the gradient has noticable gaps
ctx.lineWidth=2;
// draw a gradient-stroked line tangent to each point on the curve
for(var i=0;i<points.length;i++){
// calc the topside and bottomside points of the tangent line
var offX1=points[i].x+20*Math.cos(points[i].angle);
var offY1=points[i].y+20*Math.sin(points[i].angle);
var offX2=points[i].x+20*Math.cos(points[i].angle-PI);
var offY2=points[i].y+20*Math.sin(points[i].angle-PI);
// create a gradient stretching between
// the calculated top & bottom points
var gradient=ctx.createLinearGradient(offX1,offY1,offX2,offY2);
gradient.addColorStop(0.00, 'red');
gradient.addColorStop(1/6, 'orange');
gradient.addColorStop(2/6, 'yellow');
gradient.addColorStop(3/6, 'green')
gradient.addColorStop(4/6, 'aqua');
gradient.addColorStop(5/6, 'blue');
gradient.addColorStop(1.00, 'purple');
// draw the gradient-stroked line at this point
ctx.strokeStyle=gradient;
ctx.beginPath();
ctx.moveTo(offX1,offY1);
ctx.lineTo(offX2,offY2);
ctx.stroke();
}
// draw a top stroke to cover jaggies
// on the top of the gradient curve
var offX1=points[0].x+20*Math.cos(points[0].angle);
var offY1=points[0].y+20*Math.sin(points[0].angle);
ctx.strokeStyle="red";
// Note: increase the lineWidth if this outside of the
// gradient still has jaggies
ctx.lineWidth=1.5;
ctx.beginPath();
ctx.moveTo(offX1,offY1);
for(var i=1;i<points.length;i++){
var offX1=points[i].x+20*Math.cos(points[i].angle);
var offY1=points[i].y+20*Math.sin(points[i].angle);
ctx.lineTo(offX1,offY1);
}
ctx.stroke();
// draw a bottom stroke to cover jaggies
// on the bottom of the gradient
var offX2=points[0].x+20*Math.cos(points[0].angle+PI);
var offY2=points[0].y+20*Math.sin(points[0].angle+PI);
ctx.strokeStyle="purple";
// Note: increase the lineWidth if this outside of the
// gradient still has jaggies
ctx.lineWidth=1.5;
ctx.beginPath();
ctx.moveTo(offX2,offY2);
for(var i=0;i<points.length;i++){
var offX2=points[i].x+20*Math.cos(points[i].angle+PI);
var offY2=points[i].y+20*Math.sin(points[i].angle+PI);
ctx.lineTo(offX2,offY2);
}
ctx.stroke();
//////////////////////////////////////////
// helper functions
//////////////////////////////////////////
// calculate one XY point along Cubic Bezier at interval T
// (where T==0.00 at the start of the curve and T==1.00 at the end)
function getCubicBezierXYatT(startPt,controlPt1,controlPt2,endPt,T){
var x=CubicN(T,startPt.x,controlPt1.x,controlPt2.x,endPt.x);
var y=CubicN(T,startPt.y,controlPt1.y,controlPt2.y,endPt.y);
return({x:x,y:y});
}
// cubic helper formula at T distance
function CubicN(T, a,b,c,d) {
var t2 = T * T;
var t3 = t2 * T;
return a + (-a * 3 + T * (3 * a - a * T)) * T
+ (3 * b + T * (-6 * b + b * 3 * T)) * T
+ (c * 3 - c * 3 * T) * t2
+ d * t3;
}
// calculate the tangent angle at interval T on the curve
function bezierTangent(a, b, c, d, t) {
return (3 * t * t * (-a + 3 * b - 3 * c + d) + 6 * t * (a - 2 * b + c) + 3 * (-a + b));
};
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
I am working on doing something very similar, and I just wanted to add a couple things. markE's answer is great, but what he calls tangent lines to the curve, are actually lines normal or perpendicular to the curve. (Tangent lines are parallel, normal lines are perpendicular)
For my particular application, I am using a gradient across a line with transparency. In this case, it is important to get near pixel perfect gradient regions, as overlapping transparency will get drawn twice, changing the desired color. So instead of drawing a bunch of lines perpendicular to the curve, I divided the curve up into quadrilaterals and applied a linear gradient to each. Additionally, using these quadrilateral regions reduces the number of calls to draw you have to make, which can make it more efficient. You don't need a ton of regions to get a pretty smooth effect, and the fewer regions you use, the faster it will be able to render.
I adapted markE's code, so credit to him for that great answer. Here is the fiddle: https://jsfiddle.net/hvyt58dz/
Here is the adapted code I used:
// canvas related variables
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// variables defining a cubic bezier curve
var PI2 = Math.PI * 2;
var s = {
x: 20,
y: 30
};
var c1 = {
x: 200,
y: 40
};
var c2 = {
x: 40,
y: 200
};
var e = {
x: 270,
y: 220
};
// an array of points plotted along the bezier curve
var points = [];
// we use PI often so put it in a variable
var PI = Math.PI;
// plot 400 points along the curve
// and also calculate the angle of the curve at that point
var step_size = 100/18;
for (var t = 0; t <= 100 + 0.1; t += step_size) {
var T = t / 100;
// plot a point on the curve
var pos = getCubicBezierXYatT(s, c1, c2, e, T);
// calculate the tangent angle of the curve at that point
var tx = bezierTangent(s.x, c1.x, c2.x, e.x, T);
var ty = bezierTangent(s.y, c1.y, c2.y, e.y, T);
var a = Math.atan2(ty, tx) - PI / 2;
// save the x/y position of the point and the tangent angle
// in the points array
points.push({
x: pos.x,
y: pos.y,
angle: a
});
}
// Note: increase the lineWidth if
// the gradient has noticable gaps
ctx.lineWidth = 2;
var overlap = 0.2;
var outside_color = 'rgba(255,0,0,0.0)';
var inside_color = 'rgba(255,0,0,0.7)';
// draw a gradient-stroked line tangent to each point on the curve
var line_width = 40;
var half_width = line_width/2;
for (var i = 0; i < points.length - 1; i++) {
var x1 = points[i].x, y1 = points[i].y;
var x2 = points[i+1].x, y2 = points[i+1].y;
var angle1 = points[i].angle, angle2 = points[i+1].angle;
var midangle = (angle1 + angle2)/ 2;
// calc the topside and bottomside points of the tangent line
var gradientOffsetX1 = x1 + half_width * Math.cos(midangle);
var gradientOffsetY1 = y1 + half_width * Math.sin(midangle);
var gradientOffsetX2 = x1 + half_width * Math.cos(midangle - PI);
var gradientOffsetY2 = y1 + half_width * Math.sin(midangle - PI);
var offX1 = x1 + half_width * Math.cos(angle1);
var offY1 = y1 + half_width * Math.sin(angle1);
var offX2 = x1 + half_width * Math.cos(angle1 - PI);
var offY2 = y1 + half_width * Math.sin(angle1 - PI);
var offX3 = x2 + half_width * Math.cos(angle2)
- overlap * Math.cos(angle2-PI/2);
var offY3 = y2 + half_width * Math.sin(angle2)
- overlap * Math.sin(angle2-PI/2);
var offX4 = x2 + half_width * Math.cos(angle2 - PI)
+ overlap * Math.cos(angle2-3*PI/2);
var offY4 = y2 + half_width * Math.sin(angle2 - PI)
+ overlap * Math.sin(angle2-3*PI/2);
// create a gradient stretching between
// the calculated top & bottom points
var gradient = ctx.createLinearGradient(gradientOffsetX1, gradientOffsetY1, gradientOffsetX2, gradientOffsetY2);
gradient.addColorStop(0.0, outside_color);
gradient.addColorStop(0.25, inside_color);
gradient.addColorStop(0.75, inside_color);
gradient.addColorStop(1.0, outside_color);
//gradient.addColorStop(1 / 6, 'orange');
//gradient.addColorStop(2 / 6, 'yellow');
//gradient.addColorStop(3 / 6, 'green')
//gradient.addColorStop(4 / 6, 'aqua');
//gradient.addColorStop(5 / 6, 'blue');
//gradient.addColorStop(1.00, 'purple');
// line cap
if(i == 0){
var x = x1 - overlap * Math.cos(angle1-PI/2);
var y = y1 - overlap * Math.sin(angle1-PI/2);
var cap_gradient = ctx.createRadialGradient(x, y, 0, x, y, half_width);
ctx.beginPath();
ctx.arc(x, y, half_width, angle1 - PI, angle1);
cap_gradient.addColorStop(0.5, inside_color);
cap_gradient.addColorStop(1.0, outside_color);
ctx.fillStyle = cap_gradient;
ctx.fill();
}
if(i == points.length - 2){
var x = x2 + overlap * Math.cos(angle2-PI/2);
var y = y2 + overlap * Math.sin(angle2-PI/2);
var cap_gradient = ctx.createRadialGradient(x, y, 0, x, y, half_width);
ctx.beginPath();
ctx.arc(x, y, half_width, angle2, angle2 + PI);
cap_gradient.addColorStop(0.5, inside_color);
cap_gradient.addColorStop(1.0, outside_color);
ctx.fillStyle = cap_gradient;
ctx.fill();
console.log(x,y);
}
// draw the gradient-stroked line at this point
ctx.fillStyle = gradient;
ctx.beginPath();
ctx.moveTo(offX1, offY1);
ctx.lineTo(offX2, offY2);
ctx.lineTo(offX4, offY4);
ctx.lineTo(offX3, offY3);
ctx.fill();
}
//////////////////////////////////////////
// helper functions
//////////////////////////////////////////
// calculate one XY point along Cubic Bezier at interval T
// (where T==0.00 at the start of the curve and T==1.00 at the end)
function getCubicBezierXYatT(startPt, controlPt1, controlPt2, endPt, T) {
var x = CubicN(T, startPt.x, controlPt1.x, controlPt2.x, endPt.x);
var y = CubicN(T, startPt.y, controlPt1.y, controlPt2.y, endPt.y);
return ({
x: x,
y: y
});
}
// cubic helper formula at T distance
function CubicN(T, a, b, c, d) {
var t2 = T * T;
var t3 = t2 * T;
return a + (-a * 3 + T * (3 * a - a * T)) * T + (3 * b + T * (-6 * b + b * 3 * T)) * T + (c * 3 - c * 3 * T) * t2 + d * t3;
}
// calculate the tangent angle at interval T on the curve
function bezierTangent(a, b, c, d, t) {
return (3 * t * t * (-a + 3 * b - 3 * c + d) + 6 * t * (a - 2 * b + c) + 3 * (-a + b));
};
I'm trying to take one side of a rectangle and skew the side based on degree/angle.
I whipped up some code for you
Any questions just ask.
import flash.geom.Matrix;
var temp_matrix = new Matrix();
var square:Sprite = new Sprite();
addChild(square);
square.graphics.lineStyle(3,0x000000);
square.graphics.drawRect(0,0,200,100);
square.graphics.endFill();
var angle:Number = -10; // the angle of degrees
temp_matrix.b = Math.PI * 2 * angle / 360;// y skew
//temp_matrix.c = Math.PI * 2 * angle / 360;// x skew
var sourceMatrix:Matrix = square.transform.matrix;// get existing matrix
sourceMatrix.concat(temp_matrix); // apply skew to existing matrix
square.transform.matrix = temp_matrix;// assign the new skew
square.x = 100
square.y = 100
[SECOND ROUND]
var trapezium:Sprite = new Sprite();
addChild(trapezium);
trapezium.x = 100;
trapezium.y = 100;
var dir:Boolean = true;
var side:Boolean = true;
var angle:Number = 0; // the angle of degrees
var w:Number = 300;
var h:Number = 80;
var timer:Timer = new Timer(16);
timer.addEventListener( TimerEvent.TIMER, tick );
timer.start();
function tick(e:TimerEvent):void{
var radians:Number = Math.PI/180*angle;
trapezium.graphics.clear();
trapezium.graphics.beginFill(0x000000)
if( side){
// long side is right side
trapezium.graphics.lineTo(w,0);
trapezium.graphics.lineTo(w,radians*w+h);
trapezium.graphics.lineTo(0,h);
trapezium.graphics.lineTo(0,0);
}else{
trapezium.graphics.lineTo(w,0);
trapezium.graphics.lineTo(w,h);
trapezium.graphics.lineTo(0,radians*w+h);
trapezium.graphics.lineTo(0,0);
}
trapezium.graphics.endFill();
if(angle>=10){
dir = false;
}
if(angle<=0){
dir = true;
}
if(dir){
angle = angle+.2;
}else{
angle = angle-.2;
}
if( Math.floor(angle*10) <= 0 ){
side = !side;
}
}
Take the tangent of the angle and multiply by the width of the rectangle to get the delta y for the bottom axis so you would have
[x1,y1] as the origin of the rectangle (which never changes)
[x1+length, y1+deltaY] as the right bottom corner
Don't know AS, but after editing this looks like filled polygon with vertices:
P0 =(X0, Y0)
P1 = (X1, Y0)
if Angle >= 0 then
P2 = (X1, Y1)
P3 = (X0, Y1 + (X1-X0) * Tan(Angle))
else
P2 = (X1, Y1 - (X1-X0) * Tan(Angle))
P3 = (X0, Y1)
how come this doesn't work? does rotate only work with images?
context.moveTo(60,60);
context.lineTo(200,60);
context.lineTo(200,200);
context.lineTo(60,200);
context.lineTo(60,60);
context.stroke();
context.rotate(45 * Math.PI / 180);
context.restore();
You are rotating the whole canvas when you use context.rotate, and since the pivot point is defaulted at the coordinates (0, 0), your square sometimes will be drawn out of bounds.
By moving the pivot point to the middle of the square, you can then rotate it successfully.
Note: Make sure you rotate the canvas before you draw the square.
// pivot point coordinates = the center of the square
var cx = 130; // (60+200)/2
var cy = 130; // (60+200)/2
// Note that the x and y values of the square
// are relative to the pivot point.
var x = -70; // cx + x = 130 - 70 = 60
var y = -70; // cy + y = 130 - 70 = 60
var w = 140; // (cx + x) + w = 60 + w = 200
var h = 140; // (cy + y) + h = 60 + h = 200
var deg = 45;
context.save();
context.translate(cx, cy);
context.rotate(deg * Math.PI/180);
context.fillRect(x, y, w, h);
context.restore();
Explanation:
context.save(); saves the current state of the coordinate system.
context.translate(cx, cy); moves the pivot point.
context.rotate(deg * Math.PI/180); rotates the square to deg degrees (Note that the parameter is in radians, not degrees)
context.fillRect( x, y, w, h ); draws the square
context.restore(); restores the last state of the coordinate system.
Here is a JS Fiddle example.
Here is another JS Fiddle example that features a HTML5 slider.