Skip to content

Commit

Permalink
chore(api): Edits for arcTo() 2D canvas method examples
Browse files Browse the repository at this point in the history
  • Loading branch information
bsmth committed Dec 12, 2023
1 parent 8d675c8 commit 486d89b
Showing 1 changed file with 114 additions and 118 deletions.
232 changes: 114 additions & 118 deletions files/en-us/web/api/canvasrenderingcontext2d/arcto/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,40 @@ arcTo(x1, y1, x2, y2, radius)

None ({{jsxref("undefined")}}).

### How arcTo works
### Usage notes

There are some special cases to consider when describing the action of
`arcTo()`. Let <em>P<sub>0</sub></em> be the current point on the path when
`arcTo()` is called, <em>P<sub>1</sub></em> = (x1, y1), and
<em>P<sub>2</sub></em> = (x2, y2) be the first and second control points
respectively, and _r_ = radius be the `radius` specified in the call.

- If _r_ is negative, it is an error, and an `IndexSizeError` [DOMException](/en-US/docs/Web/API/DOMException) is raised.

- If _r_ is 0, `arcTo()` behaves as if <em>P<sub>0</sub></em>,
<em>P<sub>1</sub></em>, and <em>P<sub>2</sub></em> are collinear (in a line).

- In the case of all of the points being collinear, a line from
<em>P<sub>0</sub></em> to <em>P<sub>1</sub></em> is drawn
unless the points <em>P<sub>0</sub></em> and <em>P<sub>1</sub></em> are
coincident (on top of each other), in which case nothing is drawn.

For the usual case of _r_ being positive and <em>P<sub>0</sub></em>,
<em>P<sub>1</sub></em>, and <em>P<sub>2</sub></em> not being collinear,
drawing always consists of an arc and possibly a line connecting the current
position on the path to that arc.
To visualize how this works, an interactive demo shows the
construction of the path generated by `arcTo()` in
[Construction of `arcTo()` path](#construction_of_arcto_path).

## Examples

### How `arcTo()` works

One way to think about `arcTo()` is to imagine two straight segments: one
from the starting point to a first control point, and another from there to a second
control point. Without `arcTo()`, these two segments would form a sharp
corner: `arcTo()` creates a circular arc that fits this corner and smooths it
corner: `arcTo()` creates a circular arc at this corner and smooths it
out. In other words, the arc is tangential to both segments.

#### HTML
Expand Down Expand Up @@ -98,35 +126,86 @@ ctx.fill();
In this example, the path created by `arcTo()` is **thick and
black**. Tangent lines are gray, control points are red, and the start point is blue.

{{ EmbedLiveSample('How_arcTo_works', 315, 165) }}
{{ EmbedLiveSample('How_arcTo_works', 315, 170) }}

There are several special cases to consider when describing the action of
`arcTo()`. Let <em>P<sub>0</sub></em> be the current point on the path when
`arcTo()` is called, <em>P<sub>1</sub></em> = (x1, y1), and
<em>P<sub>2</sub></em> = (x2, y2) be the first and second control points
respectively, and _r_ = radius be the radius specified in the call.
If _r_ is negative, it is an error, and an IndexSizeError DOMException is raised.
If _r_ is 0, `arcTo()` behaves as if <em>P<sub>0</sub></em>,
<em>P<sub>1</sub></em>, and <em>P<sub>2</sub></em> are collinear.
In the case of all of the points being collinear, a line from
<em>P<sub>0</sub></em> to <em>P<sub>1</sub></em> is drawn
unless the points <em>P<sub>0</sub></em> and <em>P<sub>1</sub></em> are
coincident, in which case nothing is drawn.
### Creating a rounded corner

For the usual case of _r_ being positive and <em>P<sub>0</sub></em>,
<em>P<sub>1</sub></em>, and <em>P<sub>2</sub></em> not being collinear,
drawing always consists of an arc and possibly a line connecting the current
position on the path to that arc. The precise path that is drawn can be
determined by considering the semi-infinite lines from <em>P<sub>1</sub></em>
in the direction of <em>P<sub>0</sub></em> and from <em>P<sub>1</sub></em>
in the direction of <em>P<sub>2</sub></em> and the circle of radius _r_ that is tangent
to each line at <em>T<sub>1</sub></em> and <em>T<sub>2</sub></em> respectively.
The shorter arc along the circle between the two tangent points
<em>T<sub>1</sub></em> and <em>T<sub>2</sub></em> is drawn. If
<em>T<sub>1</sub></em> is not equal to <em>P<sub>0</sub></em>, a line is
drawn from <em>P<sub>0</sub></em> to <em>T<sub>1</sub></em> connecting the
path to the arc at the point of tangency. An interactive demo below shows the
construction of the path generated by `arcTo()`.
This example creates a rounded corner using `arcTo()`. This is one of the
method's most common uses.

#### HTML

```html
<canvas id="canvas"></canvas>
```

#### JavaScript

The arc begins at the point specified by `moveTo()`: (230, 20). It is shaped
to fit control points at (90, 130) and (20, 20), and has a radius of 50. The
`lineTo()` method connects the arc to (20, 20) with a straight line. Note
that the arc's second control point and the point specified by `lineTo()` are
the same, which produces a totally smooth corner.

```js
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const p0 = { x: 230, y: 20 };
const p1 = { x: 90, y: 130 };
const p2 = { x: 20, y: 20 };

const labelPoint = (p) => {
const offset = 10;
ctx.fillText(`(${p.x},${p.y})`, p.x + offset, p.y + offset);
};

ctx.beginPath();
ctx.lineWidth = 4;
ctx.font = "1em sans-serif";
ctx.moveTo(p0.x, p0.y);
ctx.arcTo(p1.x, p1.y, p2.x, p2.y, 50);
ctx.lineTo(p2.x, p2.y);

labelPoint(p0);
labelPoint(p1);
labelPoint(p2);

ctx.stroke();
```

#### Result

{{ EmbedLiveSample('Creating_a_rounded_corner', 315, 165) }}

### Result of a large radius

If you use a relatively large radius, the arc may appear in a place you didn't expect.
In this example, the arc's connecting line goes above, instead of below, the coordinate
specified by `moveTo()`. This happens because the radius is too large for the
arc to fit entirely below the starting point.

#### HTML

```html
<canvas id="canvas"></canvas>
```

#### JavaScript

```js
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");

ctx.beginPath();
ctx.moveTo(180, 90);
ctx.arcTo(180, 130, 110, 130, 130);
ctx.lineTo(110, 130);
ctx.stroke();
```

#### Result

{{ EmbedLiveSample('Result_of_a_large_radius', 315, 165) }}

### Construction of arcTo() path

Expand Down Expand Up @@ -185,16 +264,14 @@ be edited, and the arrow keys can be used to change an underlined element that i
* Cursor problems were also seen when text was selected before entering
* the canvas. Additional tests which may appear to be redundant in the
* code minimized these issues.
*
* NOTE: 350 X 450 is a good size with a 300 X 300 canvas
*/
"use strict";
/* Parameters for demo */
const param = {
canvasWidth: 300, // canvas size
canvasHenght: 300,
canvasHeight: 300,
hitDistance: 5, // mouse distance to be considered a hit
errorTolCenter: 1e-4, // limit on circle center differences
radiusMax: 250, // largest allowed radius
Expand Down Expand Up @@ -382,7 +459,7 @@ be edited, and the arrow keys can be used to change an underlined element that i
/* Given configuration parameters, initialize the state */
function initDemoState({
canvasWidth = 300,
canvasHenght = 300,
canvasHeight = 300,
hitDistance = 5,
errorTolCenter = 1e-4,
radiusMax = 250,
Expand All @@ -402,7 +479,7 @@ be edited, and the arrow keys can be used to change an underlined element that i
];
s.hitDistance = hitDistance;
s.errorTolCenter = errorTolCenter;
s.canvasSize = Math2D.point(canvasWidth, canvasHenght);
s.canvasSize = Math2D.point(canvasWidth, canvasHeight);
if (radius > radiusMax) {
/* limit param to allowed values */
Expand Down Expand Up @@ -533,7 +610,7 @@ be edited, and the arrow keys can be used to change an underlined element that i
/* Average the center values */
const C = Math2D.point(C1.x + 0.5 * deltaC.x, C1.y + 0.5 * deltaC.y);
/* Find the "Infinite values" of the two semi-infinite lines.
/* Find the "infinite values" of the two semi-infinite lines.
* As a practical consideration, anything off the canvas is
* infinite. A distance equal to the height + width of the canvas
* is assured to be sufficiently far away and has the advantage of
Expand Down Expand Up @@ -920,92 +997,11 @@ label {
}
```

#### Result

{{ EmbedLiveSample("Construction of arcTo() path", 350, 450) }}

## Examples

### Creating a rounded corner

This example creates a rounded corner using `arcTo()`. This is one of the
method's most common uses.

#### HTML

```html
<canvas id="canvas"></canvas>
```

#### JavaScript

The arc begins at the point specified by `moveTo()`: (230, 20). It is shaped
to fit control points at (90, 130) and (20, 20), and has a radius of 50. The
`lineTo()` method connects the arc to (20, 20) with a straight line. Note
that the arc's second control point and the point specified by `lineTo()` are
the same, which produces a totally smooth corner.

```js
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const p0 = { x: 230, y: 20 };
const p1 = { x: 90, y: 130 };
const p2 = { x: 20, y: 20 };

const labelPoint = (p) => {
const offset = 15;
ctx.fillText(`(${p.x},${p.y})`, p.x + offset, p.y + offset);
};

ctx.beginPath();
ctx.moveTo(p0.x, p0.y);
ctx.arcTo(p1.x, p1.y, p2.x, p2.y, 50);
ctx.lineTo(p2.x, p2.y);

labelPoint(p0);
labelPoint(p1);
labelPoint(p2);

ctx.stroke();
```

#### Result

{{ EmbedLiveSample('Creating_a_rounded_corner', 315, 165) }}

### Result of a large radius

If you use a relatively large radius, the arc may appear in a place you didn't expect.
In this example, the arc's connecting line goes above, instead of below, the coordinate
specified by `moveTo()`. This happens because the radius is too large for the
arc to fit entirely below the starting point.

#### HTML

```html
<canvas id="canvas"></canvas>
```

#### JavaScript

```js
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");

ctx.beginPath();
ctx.moveTo(180, 90);
ctx.arcTo(180, 130, 110, 130, 130);
ctx.lineTo(110, 130);
ctx.stroke();
```

#### Result

{{ EmbedLiveSample('Result_of_a_large_radius', 315, 165) }}

### Live demo
### Animating `arcTo()` drawing

More sophisticated demo of the method. You can play around with the arc radius to see how
For this example, you can play around with the arc radius to see how
the path changes. The path is drawn from the starting point _p0_ using `arcTo()` with control points
_p1_ and _p2_ and a radius that varies from 0 to the maximum radius selected with the slider.
Then a `lineTo()` call completes the path to _p2_.
Expand Down

0 comments on commit 486d89b

Please sign in to comment.