Sandy
Sandy

Reputation: 14125

html5 canvas change line to circle

I want to draw a rectangle/square and I want that if I drag any side of that rectangle then that side of rectangle should change to circle as shown in first image.
I managed to draw a rectangle/square with stretchable sides using Quadratic Curves but the issue is that when I stretch side of rectangle it does not stretch as circle but as elipse or something as shown in second image.
I know you might recommend using Bezier Curve but I want single control point like Quadratic Curve but bezier have two(correct me if I am wrong).

Please suggest me what should be the best approach towards this issue.

enter image description here

Image - what I wanted

enter image description here

Image - what I have achieved


What I have done
This fiddle shows result of my work.
To draw rectangle just click and drag your maouse on canvas.

Here is the code

Upvotes: 0

Views: 606

Answers (1)

Theraot
Theraot

Reputation: 40160

The higher the order of a bezier curve, the more control points it needs. Quadratic curves are second order bezier curves, and they need a single control point. Bezier curves with two control points are third order. A bezier curve of order one is effectively a straight line. No finite order of bezier curves can make a perfect circle arc.

By the way, the quadratic curve is not a "elipse or something" it is a parabolic segment.

If you want to have circle arcs, you should use... well circle arcs! To control it you will need to change the radius, in fact you could do it by moving the center of the circle.

You will need additional logic to handle the straight line, as the circle arc is never a straight line. So if the drag point is over the straight line you will draw a line, if not you will draw the arc with an appropriate radius.

So, let's say you have the following situation:

enter image description here

Where the segment ab is the straight line of your rectangle and acb is the desired arc. y is the height of the segment and x is the horizontal offset of the drag. We are looking for r the radius of the circle defined by the three points a, c and b.

Now the angle sda is a turn/4, sd is r - x and ad is y / 2. If we use Pythagoras' we get:

r^2 = (r-x)^2 + (y/2)^2
=>
r^2 = (r-x)(r-x) + (y/2)^2
=>
r^2 = r^2 - 2rx + x^2 + (y/2)^2
=>
r^2 = r^2 - 2rx + x^2 + (y^2/4)
=>
0 = - 2rx + x^2 + (y^2/4)
=>
2rx = x^2 + (y^2/4)
=>
r = (x^2 + (y^2/4)) / 2x
=>
r = ((x^2) / 2x) + ((y^2/4) / 2x)
=>
r = (x/2) + ((y^2/4) / 2x)
=>
r = (x/2) + (y^2/8x)

As you can see, when x is 0 we have division by 0. That's why you will have to switch to drawing straight lines when that happens.

We the found formula ( r = (x/2) + (y^2/8x) ) you will be able to determinate the radius of the circle to draw the arc. Finding the center point is trivial...

To find the angles you can use either the Law of Sines or the Law of cosines, at your preference, both work well. You have the choice of using the triangle asb, the triangle asd or the triangle adc (in green) to find the angles.

For a simple approach let's continue with the triangle asd, and let's use the Law of Sines:

r / sin(turn/4) = (y/2) / sin(θ/2)

Since the sine of a quarter turn is 1, we can replace it:

=>
r / 1 = (y/2) / sin(θ/2)
=>
1 = (y/2) / sin(θ/2)

Now, solve it for the angle:

=>
sin(θ/2) = (y/2)
=>
θ/2 = asin(y/2)

When calling the function to draw the arc, the starting angle will be -θ/2 and the ending angle will be θ/2.

Note: all this was made for the right side of the rectangle adjustments will be needed for the other sides.

Upvotes: 1

Related Questions