I want to draw some lines inside a circle on a canvas, in the following manner.
I have no idea how to draw the lines as showed below. But I have the basic knowledge to draw line and arcs on a canvas. How to proceed?
I want to draw some lines inside a circle on a canvas, in the following manner.
I have no idea how to draw the lines as showed below. But I have the basic knowledge to draw line and arcs on a canvas. How to proceed?
You can use a bezier curve as suggested in comments with control points, however, these can turn out to be hard to control (no pun) as they do not pass through the points you have defined and you always need to define two control points.
In order to achieve a line through points using the actual points you need to use cardinal splines.
There is no built-in support for these but a while back I made an implementation of this for JavaScript and canvas (code can be downloaded from here, MIT license).
With this you can simply define three points as a minimum (to get a simple curve) and the function will take care of drawing a smooth curve between the points with a set tension value.
If you for example defined the following three points:
var pts = [10,100, 200,50, 390,100];
You would obviously just get a simple poly-line like this if we wanted to illustrate the points (for comparison):
Using a cardinal spline with the same three points would give you this:
The following code generates the above curve (without the red dots showing the point coordinates):
ctx.beginPath();
ctx.curve(pts);
ctx.stroke();
Now it is simply a matter of moving the points around (in particular the center point) and the curve will adopt. Adding a tension slider for the user can be an advantage:
Increasing the tension to for example 0.8 give you this result:
ctx.curve(pts, 0.8);
and lowering it to for example 0.3 will reduce the smoothness to this:
ctx.curve(pts, 0.3);
There are also other parameters (see the link at top for documentation) and you can have "unlimited" number of points in the point array in case you want to add super-fine control.
The implementation extends the canvas context but you can extract the method and use it separately if you are faint at heart. :-)
I hope I am interpreting your drawing correctly here... to use the above for a circle you would simply need to do the following:
Lets say you wanted to draw lines between -70° and 70° and maximum 5 lines you could do something like this:
var ctx = canvas.getContext('2d'),
cx = canvas.width * 0.5,
cy = canvas.height * 0.5,
pts,
startAngle = -70,
endAngle = 70,
lines = 5,
angle,
range,
steps,
radius = 90,
delta = 15,
x, y,
i;
ctx.lineWidth = 3;
ctx.strokeStyle = '#059';
/// draw arc
ctx.beginPath();
ctx.arc(cx, cy, radius, 0, 2 * Math.PI);
ctx.stroke();
/// calculate angle range normalized to 0 degrees
startAngle = startAngle * Math.PI / 180;
endAngle = endAngle * Math.PI / 180;
range = endAngle - startAngle;
steps = range / (lines + 1);
/// calculate point at circle (vertical only)
for(i = 1; i <= lines; i++) {
pts = [];
/// right side
x = cx + radius * Math.cos(startAngle + steps * i);
y = cy + radius * Math.sin(startAngle + steps * i);
pts.push(x, y);
/// center
pts.push(cx, y + delta * ((y - cy)/ cy));
/// flip for left side
x = cx - (x - cx);
pts.push(x, y);
/// draw curve
ctx.beginPath();
ctx.curve(pts, 0.8);
ctx.stroke();
}
Which would result in this:
Fiddle here
It's now just a matter of playing around with the values (delta for example) and to calculate the horizontal row - I'll leave that as an exercise for the OP:
That being said - if you intended the globe to be more um, circular :-S, you could also have used a function to calculate part of an ellipse and draw that as lines instead. If would be about the same implementation as above here but with a sub function to calculate the ellipse between left and right side using the difference between the line and middle point as radius.
For example:
/// calculate point at circle (vertical only)
for(i = 1; i <= lines; i++) {
pts = [];
/// right side
x = cx + radius * Math.cos(startAngle + steps * i);
y = cy + radius * Math.sin(startAngle + steps * i);
pts.push(cx - radius, cy);
pts.push(cx, y);
pts.push(cx + radius, cy);
/// draw ellipse side
ctx.beginPath();
drawEllipseSide(pts, true);
ctx.stroke();
}
Then in the method (only vertical shown):
function drawEllipseSide(pts, horizontal) {
var radiusX,
radiusY,
cx, cy,
x, y,
startAngle,
endAngle,
steps = Math.PI * 0.01,
i = 0;
if (horizontal) {
radiusX = Math.abs(pts[4] - pts[0]) * 0.5;
radiusY = pts[3] - pts[1];
cx = pts[2];
cy = pts[1];
startAngle = 0;
endAngle = Math.PI;
x = cx + radiusX * Math.cos(startAngle);
y = cy + radiusY * Math.sin(startAngle);
ctx.moveTo(x, y);
for(i = startAngle + steps; i < endAngle; i += steps) {
x = cx + radiusX * Math.cos(i);
y = cy + radiusY * Math.sin(i);
ctx.lineTo(x, y);
}
}
}
Resulting in this (I cheat a bit in the final drawing to give a more clear picture (no pun) of what the end result will be if you continue down these lines (no pun either, I am pun-cursed) given here):
Fiddle here
My code-OCD kicked in :-P but you should at least have a few options here to go with. Study the code to see how the vertical lines are calculated and adopt that for horizontal ones.
Hope this helps!