ARCTO in SVG specification is quite different from the one we have in Canvas. I have a use case where I will have the data as per SVG spec but I need to draw that on Canvas.
I tried this but I guess my geometry is weak. Can you please help?
ARCTO in SVG specification is quite different from the one we have in Canvas. I have a use case where I will have the data as per SVG spec but I need to draw that on Canvas.
I tried this but I guess my geometry is weak. Can you please help?
The following code segment was extracted from the relevant section of Gabe Lerner's comprehensive CANVG package (see https://github.com/canvg/canvg) for any of you out there, who like me, might not want the whole nine yards of Gabe's package. Unlike the earlier solutions it is not an approximation, it is the exact equivalent of the SVG arc path element for which I would like to thank Gabe enormously.
One further point is that if you have already applied some scaling and/or translation to the canvas prior to the plotting of the path, you will need to factor this into the parameters of the two calls to Context.translate and also into the radius parameter of the call to Context.arc
When trying to map "M100,100 a25,50 -30 0,1 50,-25" to canvas use my function. Granted I wrote this with circlular arcs in mind.
ellipse(100,100,50,-25,50,false);
I had the same problem so I came across this post. The Implementation Requirements Appendix of the W3C SVG definition tells exactly how to convert form (they call it) end point parameterization to the center parameterization and back:
The SVG arc (end point parameterization) is described by:
x
andy
values of this path command)The canvas arc uses (center point parameterization):
Convert from SVG to Canvas
This means converting from SVG to canvas you can use the following equations (taken directly from the given url from W3C):
Copyright © 16 August 2011 World Wide Web Consortium, (MIT, ERCIM, Keio, Beihang). http://www.w3.org/Consortium/Legal/2015/doc-license
Edit: Modified equations for step 4.
I am now using the following equations for determining θ1 and Δθ:
This is simply the vectors between the start and end point of the arc and the center point. The φ is subtracted because of the angle is calculated before rotation. You may just leave this away if needed.
I received wrong results of the given equations but this may also be a bug in my implementation. When trying to find the bug I was thinking about what W3C is doing here. I was looking on how to calculate the angles and this was the first thing I thought about. This is leading to the correct results for me.
Convert from Canvas to SVG
I also ran into problems when using the W3C equations when converting back. This may be because of changing the angles. For getting from Canvas to SVG you need to convert the start and end angles (θ1 and θ2 = θ1 + Δθ) together with the center point to the intersections of the arc. Those are the start and end points of the SVG arc.
Compute
(x1', y1')
and(x2', y2')
This is calculating the intersection for the line which is defined by the given angle θ1/θ2 in the rotated coordinate system. For the x coordinate the + sign should be chosen, when the -π/2 ≤ θ ≤ π/2. The + sign for the y coordinate should be chosen when 0 ≤ θ ≤ π.
Compute
(x1, y1)
and(x2, y2)
The x and y coordinate of the start and end points can then be calculated by rotating back the rotation angle φ and translating the vector to the center of the ellipse.
Find the flags
The flags can easily be determined: fA is 1 if Δθ is greater than 180°, fS is 1 if Δθ is greater than 0°.
The difference between svg ellipse and canvas arc is that you have 2 radiuses in svg and only one in arcTo. Then you also need to rotate your arc on specific angle in canvas. To emulate 2 radiuses you need to make an arc with the given coordinates having the smallest radius. Then you need to scale this arc in a specific direction with coefficient(rx/ry). And now you need only to rotate. But in this approach is really hard to figurate out which part of the ellipse you want to show because it depends on the large-arc-flag and sweep-flag in svg spec. Another problem is to limit your arc by end coordinates(from svg spec). So by arcTo you can build a maximum of half of an ellipse, I guess.
You also may use a bezierCurveTo(x0,y0,x1,y1,x2,y2) to draw a part of an ellipse, if you have coordinates of 3 control points on your ellipse. With this approach you can build any segment of an ellipse. Of course, for segments more than PI you will need at least two curves
From the SVG spec you have (rx ry x-axis-rotation large-arc-flag sweep-flag x y). So the sample path would be like that:
Here you may find how bezier curves should be drawn.
Now you have a context point (which is 100,100), and an end point (which is 100+50,100-25) You need to calculate control points before rotation to -30 degrees.
Here the an example that works for me:
markup is simply:
the curves are not similar because I didnt rotate the control points to -30 degrees. But I believe that it is the only thing that you need to do. Because if you will put angle = 0. They will be similar You may use this article to get the mathematics for rotation.
PS: I took some parts of code from this answer