Adding the checked pattern to a dynamically drawn 3 player chess board - javascript

Hello you bunch of wonderful geniuses!
I seem to have reached the peak of my knowledge here and was hoping someone could point me in the right direction.
I am trying to dynamically draw a 3 player chess/checkers board using JavaScript and the HTML 5 canvas.
So far I have came up with this;
var canvas = document.getElementById('canvas')
var length = canvas.height / 2;
var center = canvas.width / 2;
var rotation = ToRadians(60);
var angle = ToRadians(30);
var height = length * Math.cos(angle);
var width = length * Math.sin(angle);
while (rotation < Math.PI * 2) {
a = [center, length];
b = [a[0] - height * Math.sin(rotation), a[1] + height * Math.cos(rotation)];
c = [b[0] + width * Math.cos(rotation), b[1] + width * Math.sin(rotation)];
d = [c[0] + width * Math.sin(angle + rotation), c[1] - width * Math.cos(angle + rotation)];
//Drawing Main Frame and 6 segments
var c2 = canvas.getContext('2d');
c2.fillStyle = '#f00';
c2.strokeStyle = "#0f0";
c2.beginPath();
c2.moveTo(a[0], a[1]);
c2.lineTo(b[0], b[1]);
c2.lineTo(c[0], c[1]);
c2.lineTo(d[0], d[1]);
c2.closePath();
c2.stroke();
//Drawing first set of divides
ab1=[((a[0]+b[0])/2),((a[1]+b[1])/2)]
cd1=[((c[0]+d[0])/2),((c[1]+d[1])/2)]
ab2=[((a[0]+ab1[0])/2),((a[1]+ab1[1])/2)]
cd2=[((d[0]+cd1[0])/2),((d[1]+cd1[1])/2)]
ab3=[((b[0]+ab1[0])/2),((b[1]+ab1[1])/2)]
cd3=[((c[0]+cd1[0])/2),((c[1]+cd1[1])/2)]
c2.beginPath();
c2.moveTo(ab1[0], ab1[1]);
c2.lineTo(cd1[0], cd1[1]);
c2.moveTo(ab2[0], ab2[1]);
c2.lineTo(cd2[0], cd2[1]);
c2.moveTo(ab3[0], ab3[1]);
c2.lineTo(cd3[0], cd3[1]);
c2.stroke();
//Drawing second set of divides
bc1=[((c[0]+b[0])/2),((c[1]+b[1])/2)]
ad1=[((a[0]+d[0])/2),((a[1]+d[1])/2)]
bc2=[((c[0]+bc1[0])/2),((c[1]+bc1[1])/2)]
ad2=[((d[0]+ad1[0])/2),((d[1]+ad1[1])/2)]
bc3=[((b[0]+bc1[0])/2),((b[1]+bc1[1])/2)]
ad3=[((a[0]+ad1[0])/2),((a[1]+ad1[1])/2)]
c2.beginPath();
c2.moveTo(bc1[0], bc1[1]);
c2.lineTo(ad1[0], ad1[1]);
c2.moveTo(bc2[0], bc2[1]);
c2.lineTo(ad2[0], ad2[1]);
c2.moveTo(bc3[0], bc3[1]);
c2.lineTo(ad3[0], ad3[1]);
c2.stroke();
rotation += ToRadians(60);
}
function ToRadians(degrees) {
return degrees / (180 / Math.PI);
}
Fiddle: http://jsfiddle.net/yd7Wv/6529/
I'm quite please with the code so far but I've come to the point when I need to add the checked pattern and I am completely stumped. I literally have no idea how to go about doing this and so was wondering if someone could point me in the right direction.
I know there is a general consensus on here that people should show attempts to do it themselves but I simply can't!
Any pointers would be appreciated.
Cheers

What you are looking at is closely related to a quadrilateral transform.
You can look at one segment ("triangle") as a quadrant just distorted in perspective.
Fiddle demo
Which produces this result:
Lets begin with defining some variables we need for calculation and looping.
var w = canvas.width, // width
h = canvas.height, // height
cx = w * 0.5, // center of board
cy = h * 0.5,
r = cx * 0.9, // radius of board
pi2 = Math.PI * 2, // cache
segments = 6, // a hexagon based shape so 6
segment = pi2 / segments, // angle of each segment
hSegment = segment * 0.5, // half segment for center line
ul, ur, bl, br, // quad. corners
check = 0.25, // interpolation interval (one check)
yc = 0, xc = 0, // interpolation counters
toggle = false, // for color
x, y = 0, i = 0; // counters...
Lets define a single quadrilateral square by defining the corners of its outer boundaries:
First corner would be center of board so that one is simple:
var ul = {
x: cx,
y: cy}
Second corner would be upper right:
ur = {
x: cx + r * Math.cos(hSegment) * 0.865,
y: cy + r * Math.sin(hSegment) * 0.865
};
Third bottom right:
br = {
x: cx + r * Math.cos(segment),
y: cy + r * Math.sin(segment)
};
And last, bottom left:
bl = {
x: cx + r * Math.cos(hSegment + segment) * 0.865,
y: cy + r * Math.sin(hSegment + segment) * 0.865
};
If we draw out this shape we will get this:
Now that we have the corners we simply interpolate each line in the "square" by the check interval (0.25) which will give us in total 5 lines. We will only count 4 but we will also use the next line with the current value.
To interpolate two points we use a simple function which takes two points and a normalized value [0.0, 1.0]:
function getInt(p1, p2, t) {
return {
x: p1.x + (p2.x - p1.x) * t,
y: p1.y + (p2.y - p1.y) * t,
}
}
We create a loop to iterate through y and x points so we can do this in a systematic fashion:
for(y = 0, yc = 0; y < 4; y++) {
for(x = 0, xc = 0; x < 4; x++) {
// for upper lines (ul-ur), get first row:
var l1a = getInt(ul, bl, yc),
l1b = getInt(ur, br, yc),
l2a = getInt(ul, bl, yc + check),
l2b = getInt(ur, br, yc + check),
c1 = getInt(l1a, l1b, xc),
c2 = getInt(l1a, l1b, xc + check),
c3 = getInt(l2a, l2b, xc + check),
c4 = getInt(l2a, l2b, xc);
... draw shape ...
xc += check;
}
yc += check;
}
This section:
var l1a = getInt(ul, bl, yc), // current line [0, 3]
l1b = getInt(ur, br, yc),
l2a = getInt(ul, bl, yc + check), // next line [1, 4]
l2b = getInt(ur, br, yc + check),
calculates the interpolated points on the outer vertical lines. This gives us two new points which we then use to calculate a point on horizontal line and enables us to calculate each corner point for a "check":
c1 = getInt(l1a, l1b, xc), // corner 1 UL
c2 = getInt(l1a, l1b, xc + check), // corner 2 UR (next line)
c3 = getInt(l2a, l2b, xc + check), // corner 3 BR (next line)
c4 = getInt(l2a, l2b, xc); // corner 4 BL
Now we simply draw a polygon between those corners and fill:
ctx.beginPath();
ctx.moveTo(c1.x, c1.y);
ctx.lineTo(c2.x, c2.y);
ctx.lineTo(c3.x, c3.y);
ctx.lineTo(c4.x, c4.y);
ctx.fillStyle = toggle ? '#000' : '#fff';
To alter the color we use a toggle switch.
This single segment will look like this:
The next step is to draw all segments. We re-use the code above and simply rotate the canvas one segment for each time and do an extra toggle.
When all code is put together we get this:
for(; i < segments; i++) { // loop six segments
toggle = !toggle; // alter color each segment
// loop quadrilateral grid 4x4 cells (5x5 lines exclusive)
for(y = 0, yc = 0; y < 4; y++) {
for(x = 0, xc = 0; x < 4; x++) {
// for upper lines (ul-ur), get first row:
var l1a = getInt(ul, bl, yc),
l1b = getInt(ur, br, yc),
l2a = getInt(ul, bl, yc + check),
l2b = getInt(ur, br, yc + check),
c1 = getInt(l1a, l1b, xc),
c2 = getInt(l1a, l1b, xc + check),
c3 = getInt(l2a, l2b, xc + check),
c4 = getInt(l2a, l2b, xc);
ctx.beginPath();
ctx.moveTo(c1.x, c1.y);
ctx.lineTo(c2.x, c2.y);
ctx.lineTo(c3.x, c3.y);
ctx.lineTo(c4.x, c4.y);
ctx.fillStyle = toggle ? '#000' : '#fff';
ctx.fill();
toggle = !toggle;
xc += check;
}
yc += check; // next segment line
toggle = !toggle; // toggle per line as well
}
ctx.translate(cx, cy); // translate to center
ctx.rotate(segment); // rotate one segment
ctx.translate(-cx, -cy); // translate back
}
Now you can simply draw an outline if you wish and so forth.

Related

Calculate the center point of a arc wedge

I've drawn an arc made up of individual wedges:
I need to draw an image at the center of each wedge. Using drawImage() I need to find the canvas coordinates of the center of each wedge.
Initially I thought I could begin drawing another arc that only reaches to the center of the wedge and retrieve the context position, but I don't think that's possible.
I'm no math wiz and I assume this will involve some trig, but I'm not quite certain where to start here. Any advice?
Here is one way you can do this:
Calculate the average radius by ar = (r1 + r2) / 2. This will give the center perpendicular to arc's center point.
Calculate the average angle by aa = (a1 + a2) / 2. This will give the center point between the two wedge edges. Note that this has edge cases (no pun) where the second angle may be smaller than the first angle which will cause the average to "wrap around". Always use a1 for the smallest angle and if a2 is smaller add 360° (or 2 x π in radian) to a2.
With these two values we can calculate center x and y using:
x = centerX + cos(aa) * ar;
y = centerY + sin(aa) * ar;
Examples
var ctx = c.getContext("2d");
var r1 = 100; // inner radius
var r2 = 140; // outer radius
var a1 = Math.PI + 0.1; // start angle
var a2 = Math.PI + 0.6; // end angle
var cx = 150; // arc center point
var cy = 150;
// render the wedge
ctx.arc(cx, cy, r1, a1, a2);
ctx.arc(cx, cy, r2, a2, a1, true);
ctx.closePath();
ctx.stroke();
// calculate center point
var r = (r1 + r2) * 0.5; // avr. radius
var a = (a1 + (a2 > a1 ? a2 : a2 + Math.PI*2)) * 0.5; // avr. angle + special case
var x = cx + Math.cos(a) * r; // use angle and radius for
var y = cy + Math.sin(a) * r; // new center point in wedge
// plot center point
ctx.fillStyle = "red";
ctx.fillRect(x-1, y-1, 3, 3);
<canvas id=c></canvas>
Edge case:
var ctx = c.getContext("2d");
var r1 = 100;
var r2 = 140;
var a1 = Math.PI * 2 - 0.2;
var a2 = 0.4;
var cx = 150;
var cy = 75;
// render the wedge
ctx.arc(cx, cy, r1, a1, a2);
ctx.arc(cx, cy, r2, a2, a1, true);
ctx.closePath();
ctx.stroke();
// calculate center point
var r = (r1 + r2) * 0.5;
var a = (a1 + (a2 > a1 ? a2 : a2 + Math.PI*2)) * 0.5;
var x = cx + Math.cos(a) * r;
var y = cy + Math.sin(a) * r;
// plot center point
ctx.fillStyle = "red";
ctx.fillRect(cx, cy, 200, 1);
ctx.fillText("0°", cx, cy - 2);
ctx.fillRect(x-1, y-1, 3, 3);
<canvas id=c></canvas>

How to draw parallel edges (arrows) between vertices with canvas?

I'm working on a flow-network visualization with Javascript.
Vertices are represented as circles and edges are represented as arrows.
Here is my Edge class:
function Edge(u, v) {
this.u = u; // start vertex
this.v = v; // end vertex
this.draw = function() {
var x1 = u.x;
var y1 = u.y;
var x2 = v.x;
var y2 = v.y;
context.beginPath();
context.moveTo(x1, y1);
context.lineTo(x2, y2);
context.stroke();
var dx = x1 - x2;
var dy = y1 - y2;
var length = Math.sqrt(dx * dx + dy * dy);
x1 = x1 - Math.round(dx / ((length / (radius))));
y1 = y1 - Math.round(dy / ((length / (radius))));
x2 = x2 + Math.round(dx / ((length / (radius))));
y2 = y2 + Math.round(dy / ((length / (radius))));
// calculate the angle of the edge
var deg = (Math.atan(dy / dx)) * 180.0 / Math.PI;
if (dx < 0) {
deg += 180.0;
}
if (deg < 0) {
deg += 360.0;
}
// calculate the angle for the two triangle points
var deg1 = ((deg + 25 + 90) % 360) * Math.PI * 2 / 360.0;
var deg2 = ((deg + 335 + 90) % 360) * Math.PI * 2 / 360.0;
// calculate the triangle points
var arrowx = [];
var arrowy = [];
arrowx[0] = x2;
arrowy[0] = y2;
arrowx[1] = Math.round(x2 + 12 * Math.sin(deg1));
arrowy[1] = Math.round(y2 - 12 * Math.cos(deg1));
arrowx[2] = Math.round(x2 + 12 * Math.sin(deg2));
arrowy[2] = Math.round(y2 - 12 * Math.cos(deg2));
context.beginPath();
context.moveTo(arrowx[0], arrowy[0]);
context.lineTo(arrowx[1], arrowy[1]);
context.lineTo(arrowx[2], arrowy[2]);
context.closePath();
context.stroke();
context.fillStyle = "black";
context.fill();
};
}
Given the code
var canvas = document.getElementById('canvas'); // canvas element
var context = canvas.getContext("2d");
context.lineWidth = 1;
context.strokeStyle = "black";
var radius = 20; // vertex radius
var u = {
x: 50,
y: 80
};
var v = {
x: 150,
y: 200
};
var e = new Edge(u, v);
e.draw();
The draw() function will draw an edge between two vertices like this:
If we add the code
var k = new Edge(v, u);
k.draw();
We will get:
but I want to draw edges both directions as following:
(sorry for my bad paint skills)
Of course the vertices and the edge directions are not fixed.
A working example (with drawing vertex fucntion) on JSFiddle:
https://jsfiddle.net/Romansko/0fu01oec/18/
Aligning axis to a line.
It can make everything a little easier if you rotate the rendering to align with the line. Once you do that it is then easy to draw above or below the line as that is just in the y direction and along the line is the x direction.
Thus if you have a line
const line = {
p1 : { x : ? , y : ? },
p2 : { x : ? , y : ? },
};
Convert it to a vector and normalise that vector
// as vector from p1 to p2
var nx = line.p2.x - line.p1.x;
var ny = line.p2.y - line.p1.y;
// then get length
const len = Math.sqrt(nx * nx + ny * ny);
// use the length to normalise the vector
nx /= len;
ny /= len;
The normalised vector represents the new x axis we want to render along, and the y axis is at 90 deg to that. We can use setTransform to set both axis and the origin (0,0) point at the start of the line.
ctx.setTransform(
nx, ny, // the x axis
-ny, nx, // the y axis at 90 deg to the x axis
line.p1.x, line.p1.y // the origin (0,0)
)
Now rendering the line and arrow heads is easy as they are axis aligned
ctx.beginPath();
ctx.lineTo(0,0); // start of line
ctx.lineTo(len,0); // end of line
ctx.stroke();
// add the arrow head
ctx.beginPath();
ctx.lineTo(len,0); // tip of arrow
ctx.lineTo(len - 10, 10);
ctx.lineTo(len - 10, -10);
ctx.fill();
To render two lines offset from the center
var offset = 10;
ctx.beginPath();
ctx.lineTo(0,offset); // start of line
ctx.lineTo(len,offset); // end of line
ctx.moveTo(0,-offset); // start of second line
ctx.lineTo(len,-offset); // end of second line
ctx.stroke();
// add the arrow head
ctx.beginPath();
ctx.lineTo(len,offset); // tip of arrow
ctx.lineTo(len - 10, offset+10);
ctx.lineTo(len - 10, offset-10);
ctx.fill();
offset = -10;
// add second arrow head
ctx.beginPath();
ctx.lineTo(0,offset); // tip of arrow
ctx.lineTo(10, offset+10);
ctx.lineTo(10, offset-10);
ctx.fill();
And you can reset the transform with
ctx.setTransform(1,0,0,1,0,0); // restore default transform

How to find the control point of a quadratic curve using a parabola?

I can't figure out how to draw a parabola which is having a equation as y^2 = 4ax
So I have both end points i.e. P0, P2, however I can't figure out how to find control point to put in quadraticCurveTo() function.
To match a quadratic Bezier to this parabola formula and assuming origin is 0, you can use place the control point at -y0 or -y1 from one of the end points.
Example
First, lets rearrange the formula:
y2 = 4ax
to:
x = y2 / 4a
so we can plot from bottom down.
In this case we can simply boil down everything and use the inverse of y and mid x as control point.
The general principle though, is to find the tangents of the endpoints. Then where the lines from those intersect the control-point should be placed. If you want the mathematical steps on how to find the intersection I would recommend taking a look at Erik Man's answer here (which happened to be posted today but breaks down the math in much more details).
So, if we plot it within the window of a canvas (black is parabola, red is quadratic curve):
var ctx = document.querySelector("canvas").getContext("2d"),
w = ctx.canvas.width, h = ctx.canvas.height;
ctx.strokeStyle = "red";
ctx.lineWidth = 2;
ctx.translate(0, 6);
// formula
function f(y, a) {return y * y / (a * 4)};
var a = 80;
plotWindow();
function plotWindow() {
ctx.clearRect(0, -6, w, h);
ctx.fillStyle = "#000";
// plot parabola using formula
for(var i = 0; i < w; i++) {
var y = f(i - w * 0.5, a);
ctx.fillRect(i - 2, y - 2, 4, 4);
}
// plot parabola using quadratic curve:
var x0 = 0;
var y0 = f(-w * 0.5, a);
var x1 = w;
var y1 = f( w * 0.5, a);
var cx = x1 * 0.5; // control point is center for x
var cy = -y0; // control point is -y0 for y assuming top of parabola = 0
ctx.beginPath();
ctx.moveTo(x0, y0);
ctx.quadraticCurveTo(cx, cy, x1, y1);
ctx.stroke();
// plot a
ctx.fillStyle = "blue";
ctx.fillRect(cx - 3, a - 3, 6, 6);
ctx.fillText("a=" + a, cx + 6, a + 5)
}
// slider
document.querySelector("input").onchange = function() {
a = +this.value;
plotWindow();
};
canvas {border:1px solid #777}
<script src="https://cdn.rawgit.com/epistemex/slider-feedback/master/sliderfeedback.min.js"></script>
<label>a: <input type="range" min=10 max=172 value=80></label><br>
<canvas width=600 height=190></canvas>

How can I generate a rainbow circle using HTML5 canvas?

I would like to generate a canvas image using gradients in some clever way. I would like the image to looks something like this:
I just can't get my head around it. I need to generate lines in the form and arc - or use gradients with color stops in some clever way. Maybe it would be a lot easier if I converted to HSL and just go through the HUE values?
For example in a rectangle format I could
for (var i = 0; i < h; ++i) {
var ratio = i/h;
var hue = Math.floor(360*ratio);
var sat = 100;
var lum = 50;
line(dc, hslColor(hue,sat,lum), left_margin, top_margin+i, left_margin+w, top_margin+i);
}
Does anybody have any clever tips on how to produce this image using canvas?
This is not perfect (due to drawing steps ...), but it can help you :
http://jsfiddle.net/afkLY/2/
HTML:
<canvas id="colors" width="200" height="200"></canvas>
Javascript:
var canvas = document.getElementById("colors");
var graphics = canvas.getContext("2d");
var CX = canvas.width / 2,
CY = canvas.height/ 2,
sx = CX,
sy = CY;
for(var i = 0; i < 360; i+=0.1){
var rad = i * (2*Math.PI) / 360;
graphics.strokeStyle = "hsla("+i+", 100%, 50%, 1.0)";
graphics.beginPath();
graphics.moveTo(CX, CY);
graphics.lineTo(CX + sx * Math.cos(rad), CY + sy * Math.sin(rad));
graphics.stroke();
}
The idea is to draw the disc line by line with a hue value corresponding to the line direction.
You can change the color base rotation by adding a radius angle to rad variable (adding -pi/2 to rad would make the gradient look like your figure).
EDIT:
I made a new demo that generalizes the concept a bit and renders a rainbow polygon. Here is the CodePen.
To get rid of the small voids beteween the colors, I used quads that overflow to the next color part, except for the last one.
Small adjustment to make it have a white center
var canvas = document.getElementById('colorPicker');
var graphics = canvas.getContext("2d");
var CX = canvas.width / 2,
CY = canvas.height / 2,
sx = CX,
sy = CY;
for (var i = 0; i < 360; i += 0.1) {
var rad = i * (2 * Math.PI) / 360;
var grad = graphics.createLinearGradient(CX, CY, CX + sx * Math.cos(rad), CY + sy * Math.sin(rad));
grad.addColorStop(0, "white");
grad.addColorStop(0.01, "white");
grad.addColorStop(0.99, "hsla(" + i + ", 100%, 50%, 1.0)");
grad.addColorStop(1, "hsla(" + i + ", 100%, 50%, 1.0)");
graphics.strokeStyle = grad;
graphics.beginPath();
graphics.moveTo(CX, CY);
graphics.lineTo(CX + sx * Math.cos(rad), CY + sy * Math.sin(rad));
graphics.stroke();
}
Here is an alternate approach that takes a slightly more functional approach:
var canvas = document.getElementById("radial"),
ctx = canvas.getContext("2d"),
width = canvas.width,
height = canvas.height,
center = { x: width/2, y: height/2 },
diameter = Math.min(width, height);
var distanceBetween = function(x1,y1,x2,y2) {
// Get deltas
var deltaX = x2 - x1,
deltaY = y2 - y1;
// Calculate distance from center
return Math.sqrt(deltaX*deltaX+deltaY*deltaY);
}
var angleBetween = function(x1,y1,x2,y2) {
// Get deltas
var deltaX = x2 - x1,
deltaY = y2 - y1;
// Calculate angle
return Math.atan2(deltaY, deltaX);
}
var radiansToDegrees = _.memoize(function(radians) {
// Put in range of [0,2PI)
if (radians < 0) radians += Math.PI * 2;
// convert to degrees
return radians * 180 / Math.PI;
})
// Partial application of center (x,y)
var distanceFromCenter = _.bind(distanceBetween, undefined, center.x, center.y)
var angleFromCenter = _.bind(angleBetween, undefined, center.x, center.y)
// Color formatters
var hslFormatter = function(h,s,l) { return "hsl("+h+","+s+"%,"+l+"%)"; },
fromHue = function(h) { return hslFormatter(h,100,50); };
// (x,y) => color
var getColor = function(x,y) {
// If distance is greater than radius, return black
return (distanceFromCenter(x,y) > diameter/2)
// Return black
? "#000"
// Determine color
: fromHue(radiansToDegrees(angleFromCenter(x,y)));
};
for(var y=0;y<height;y++) {
for(var x=0;x<width;x++) {
ctx.fillStyle = getColor(x,y);
ctx.fillRect( x, y, 1, 1 );
}
}
It uses a function to calculate the color at each pixel – not the most efficient implementation, but perhaps you'll glean something useful from it.
Note it uses underscore for some helper functions like bind() – for partial applications – and memoize.
Codepen for experimentation.

create beziers curve with only start and endpoint

I'm trying to create a html canvas where the user can define a start- and endpoint, between the start and endpoint I want to draw a waved line, I'm doing this by drawing bezierCurveTo.
a sample:
the code I use to draw this is the following:
var wave = new Kinetic.Shape({
drawFunc: function (canvas) {
var ctx = canvas.getContext();
ctx.beginPath();
ctx.moveTo(50, 50);
var waveCount = 0;
var controlPoint1X = 55;
var controlPoint2X = 60;
var endPointX = 65;
while(waveCount < 10) {
ctx.bezierCurveTo(controlPoint1X, 35, controlPoint2X, 65, endPointX, 50);
controlPoint1X += 20;
controlPoint2X += 20;
endPointX += 20;
waveCount++;
}
ctx.stroke(_this);
},
stroke: '#000000',
strokeWidth: 2
});
I can make this work as long as only the x or only the y coordinate changes. Now I want to be able to create a waved line like shown above but with a different x,y coordinate. For example startpoint x: 50 y: 50 and endpoint x: 100 y: 100. I know I have to calculate the controlpoints, but I can't find out what formula I have to use. Can someone help me out?
Let's simulate a circle and sinewave on a straight line. For a semi-circle, each "period" consists of two segments, with segment one being:
cDist = 4/3 * amplitude
(we know this from http://pomax.github.com/bezierinfo/#circles_cubic)
S = (x1, 0),
C1 = (x1, cDist)
C2 = (x2, cDist)
E = (x2, 0)
and segment two being:
S = (x2, 0),
C1 = (x2, -cDist)
C2 = (x3, -cDist)
E = (x3, 0)
For a sine wave, the control points are almost the same; the y coordinate stays at the same height, but we need to shift the x coordinates so that the shape has the corrected angle at the start and end points (for a circle they're vertical, for a sine wave they're diagonal):
S = (x1, 0),
C1 = (x1 + cDist/2, cDist)
C2 = (x2 - cDist/2, cDist)
E = (x2, 0)
and segment two is:
S = (x2, 0),
C1 = (x2+cDist, -cDist)
C2 = (x3-cDist, -cDist)
E = (x3, 0)
I put up a demonstrator of this at: http://jsfiddle.net/qcUyC/6
If you want these lines to be at a fixed angle, my advice is: rotate your context. Don't actually change your coordinates. Just use context.rotate(...) and you're done. See http://jsfiddle.net/qcUyC/7
But, if you absolutely need coordinates that aren't just drawn in the right place, but have coordinates that represent a real angled line, then start with your angle:
angle = some value you picked, in radians (somewhere between 0 and 2*pi)
with that angle, we can place our points:
dx = some fixed value we pick
dy = some fixed value we pick
ox = the x-offset w.r.t. 0 for the first coordinate in our line
oy = the y-offset w.r.t. 0 for the first coordinate in our line
x1 = ox
y1 = oy
x2 = (dx * cos(angle) - dy * sin(angle)) + ox
y2 = (dx * sin(angle) + dy * cos(angle)) + oy
x3 = (2*dx * cos(angle) - 2*dy * sin(angle)) + ox
y3 = (2*dx * sin(angle) + 2*dy * cos(angle)) + oy
...
xn = ((n-1)*dx * cos(angle) - (n-1)*dy * sin(angle)) + ox
yn = ((n-1)*dx * sin(angle) + (n-1)*dy * cos(angle)) + oy
you then have to treat your control points as vectors relative to the start point in your segments, so C1' = C1-S, and C2' = C2-S, and then you rotate those with the same transformation. You then add those vectors back up to your starting point and you now have the correctly rotated control point.
That said, don't do that. Let the canvas2d API do the rotation for you and just draw straight lines. It makes life so much easier.

Categories