diff --git a/.vscode/dictionaries/proper-names.txt b/.vscode/dictionaries/proper-names.txt
index ede18e37ca5e085..7c4a3a296500713 100644
--- a/.vscode/dictionaries/proper-names.txt
+++ b/.vscode/dictionaries/proper-names.txt
@@ -627,6 +627,7 @@ wisedog
Wolenetz
Wrox
XAMPP
+Xandar
Xavi
Xiluodu
Xiowan
diff --git a/.vscode/dictionaries/terms-abbreviations.txt b/.vscode/dictionaries/terms-abbreviations.txt
index e20bae2cfe88057..162c3604a33c277 100644
--- a/.vscode/dictionaries/terms-abbreviations.txt
+++ b/.vscode/dictionaries/terms-abbreviations.txt
@@ -304,6 +304,7 @@ ICANN
ICNS
iconset
idents
+IDOR
IERS
IMSC
Indo-Pacific
diff --git a/files/en-us/games/techniques/3d_on_the_web/glsl_shaders/index.md b/files/en-us/games/techniques/3d_on_the_web/glsl_shaders/index.md
index db5836a14a87359..d2770ee8f33af8d 100644
--- a/files/en-us/games/techniques/3d_on_the_web/glsl_shaders/index.md
+++ b/files/en-us/games/techniques/3d_on_the_web/glsl_shaders/index.md
@@ -5,7 +5,7 @@ page-type: guide
sidebar: games
---
-Shaders use GLSL (OpenGL Shading Language), a special OpenGL Shading Language with syntax similar to C. GLSL is executed directly by the graphics pipeline. There are [several kinds of shaders](https://www.khronos.org/opengl/wiki/Shader), but two are commonly used to create graphics on the web: Vertex Shaders and Fragment (Pixel) Shaders. Vertex Shaders transform shape positions into 3D drawing coordinates. Fragment Shaders compute the renderings of a shape's colors and other attributes.
+Shaders use GLSL (OpenGL Shading Language), a special OpenGL Shading Language with syntax similar to C. GLSL is executed directly by the graphics pipeline. There are [several kinds of shaders](https://wikis.khronos.org/opengl/Shader), but two are commonly used to create graphics on the web: Vertex Shaders and Fragment (Pixel) Shaders. Vertex Shaders transform shape positions into 3D drawing coordinates. Fragment Shaders compute the renderings of a shape's colors and other attributes.
GLSL is not as intuitive as JavaScript. GLSL is strongly typed and there is a lot of math involving vectors and matrices. It can get very complicated — very quickly. In this article we will make a simple code example that renders a cube. To speed up the background code we will be using the Three.js API.
diff --git a/files/en-us/learn_web_development/core/accessibility/html/index.md b/files/en-us/learn_web_development/core/accessibility/html/index.md
index e0f1b247c1d9214..dd4ddee1e5fa0e3 100644
--- a/files/en-us/learn_web_development/core/accessibility/html/index.md
+++ b/files/en-us/learn_web_development/core/accessibility/html/index.md
@@ -21,7 +21,7 @@ A great deal of web content can be made accessible just by making sure the corre
Use semantic HTML, aka "The right element for the right job", because the browser provides so many built-in accessibility hooks.
-
Accessible best practices such as alt text, good link best, form labels, and table row and column headings and scoping.
+
Accessible best practices such as alt text, good link text, form labels, and table row and column headings and scoping.
Using simple plain language, steering clear of slang and abbreviations where possible, and providing definitions where it is not possible.
The concept and practice of keyboard accessibility.
The importance of source order.
diff --git a/files/en-us/learn_web_development/core/css_layout/fundamental_layout_comprehension/index.md b/files/en-us/learn_web_development/core/css_layout/fundamental_layout_comprehension/index.md
index 81b819a04ce00d6..9cff46077b3c563 100644
--- a/files/en-us/learn_web_development/core/css_layout/fundamental_layout_comprehension/index.md
+++ b/files/en-us/learn_web_development/core/css_layout/fundamental_layout_comprehension/index.md
@@ -45,61 +45,62 @@ We are going to get you to solve this challenge in your local development enviro
An Exciting Blog Post
- Veggies es bonus vobis, proinde vos postulo essum magis kohlrabi
- welsh onion daikon amaranth tatsoi tomatillo melon azuki bean
- garlic.
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non
+ justo at erat egestas porttitor vel nec tortor. Mauris in molestie
+ ipsum. Vivamus diam elit, ornare ornare nisi vitae, ullamcorper
+ pharetra ligula. In vel lacus quis nulla sollicitudin pellentesque.
- Turnip greens yarrow ricebean rutabaga endive cauliflower sea
- lettuce kohlrabi amaranth water spinach avocado daikon napa
- asparagus winter purslane kale. Celery potato scallion desert
- raisin horseradish spinach carrot soko. Lotus root water spinach
- fennel kombu maize bamboo shoot green bean swiss chard seakale
- pumpkin onion chickpea gram corn pea. Brussels sprout coriander
- water chestnut gourd swiss chard wakame kohlrabi beetroot carrot
- watercress. Corn amaranth salsify bunya nuts nori azuki bean
- chickweed potato bell pepper artichoke.
+ Nunc vitae eleifend odio, eget tincidunt sem. Cras et varius justo.
+ Nulla sollicitudin quis urna vitae efficitur. Pellentesque
+ hendrerit molestie arcu sit amet lacinia. Vivamus vulputate sed
+ purus at eleifend. Phasellus malesuada sem vel libero hendrerit,
+ sed finibus massa porta. Vestibulum luctus scelerisque libero, sit
+ amet sagittis eros sollicitudin ac. Class aptent taciti sociosqu ad
+ litora torquent per conubia nostra, per inceptos himenaeos.
- Gumbo beet greens corn soko endive gumbo gourd. Parsley shallot
- courgette tatsoi pea sprouts fava bean collard greens dandelion
- okra wakame tomato. Dandelion cucumber earthnut pea peanut soko
- zucchini.
+ Phasellus tincidunt eros iaculis, feugiat mi at, eleifend mauris.
+ Quisque porttitor lacus eu massa condimentum, eu tincidunt nisl
+ consequat. Nunc egestas lacus dolor, id scelerisque ante tincidunt
+ ac. In risus massa, sodales ac enim eu, iaculis eleifend lorem.
- Nori grape silver beet broccoli kombu beet greens fava bean potato
- quandong celery. Bunya nuts black-eyed pea prairie turnip leek
- lentil turnip greens parsnip. Sea lettuce lettuce water chestnut
- eggplant winter purslane fennel azuki bean earthnut pea sierra
- leone bologi leek soko chicory celtuce parsley jícama salsify.
+ Maecenas euismod condimentum enim, non rhoncus neque tempor ut.
+ Vestibulum eget nisi ornare, vehicula felis id, aliquet nibh. Donec
+ in mauris in diam aliquam commodo nec ac nunc. Aliquam nisl risus,
+ eleifend a iaculis id, tempor vel tortor. Nam ullamcorper dictum
+ tellus id rhoncus. Sed quis nulla in mi aliquam euismod nec eu
+ metus.
- Celery quandong swiss chard chicory earthnut pea potato. Salsify
- taro catsear garlic gram celery bitterleaf wattle seed collard
- greens nori. Grape wattle seed kombu beetroot horseradish carrot
- squash brussels sprout chard.
+ Nam orci nulla, convallis aliquet ante ut, lobortis hendrerit
+ risus. Nulla malesuada porta turpis in consequat. Duis suscipit
+ nulla a mauris pellentesque vehicula. Fusce euismod, mi malesuada
+ venenatis vestibulum, metus erat faucibus dui, vel rutrum turpis
+ nibh ut diam.
- Veggies es bonus vobis, proinde vos postulo essum magis kohlrabi
- welsh onion daikon amaranth tatsoi tomatillo melon azuki bean
- garlic.
+ Nam ornare et mauris eget tincidunt. Nam ornare et mauris eget
+ tincidunt. Donec et ipsum a orci elementum commodo et ut ex.
+ Vivamus porttitor sem in purus maximus, eu imperdiet felis
+ lobortis.
- Turnip greens yarrow ricebean rutabaga endive cauliflower sea
- lettuce kohlrabi amaranth water spinach avocado daikon napa
- asparagus winter purslane kale. Celery potato scallion desert
- raisin horseradish spinach carrot soko. Lotus root water spinach
- fennel kombu maize bamboo shoot green bean swiss chard seakale
- pumpkin onion chickpea gram corn pea. Brussels sprout coriander
- water chestnut gourd swiss chard wakame kohlrabi beetroot carrot
- watercress. Corn amaranth salsify bunya nuts nori azuki bean
- chickweed potato bell pepper artichoke.
+ Pellentesque ullamcorper dolor ut ullamcorper convallis. Duis a
+ orci aliquet, pretium neque ut, auctor purus. Proin viverra
+ tincidunt nisi id fringilla. Maecenas interdum risus in ultricies
+ finibus. Vestibulum volutpat tincidunt libero, a feugiat leo
+ suscipit in. Sed eget lacus rutrum, semper ligula a, vestibulum
+ ipsum. Mauris in odio fringilla, accumsan eros blandit, mattis
+ odio. Ut viverra mollis augue, vitae ullamcorper velit hendrerit
+ eu. Curabitur mi lacus, condimentum in auctor sed, ornare sed leo.
@@ -126,8 +127,8 @@ We are going to get you to solve this challenge in your local development enviro
}
body {
- background-color: #fff;
- color: #333;
+ background-color: white;
+ color: #333333;
margin: 0;
font: 1.2em / 1.6 sans-serif;
}
@@ -151,7 +152,7 @@ We are going to get you to solve this challenge in your local development enviro
}
nav {
- background-color: #000;
+ background-color: black;
padding: 0.5em;
}
@@ -162,7 +163,7 @@ We are going to get you to solve this challenge in your local development enviro
}
nav a {
- color: #fff;
+ color: white;
text-decoration: none;
padding: 0.5em 1em;
}
@@ -223,8 +224,8 @@ The finished CSS looks like so:
}
body {
- background-color: #fff;
- color: #333;
+ background-color: white;
+ color: #333333;
margin: 0;
font: 1.2em / 1.6 sans-serif;
}
@@ -252,7 +253,7 @@ img {
}
nav {
- background-color: #000;
+ background-color: black;
padding: 0.5em;
/* 2. Make navigation bar stick to top of viewport */
top: 0;
@@ -270,7 +271,7 @@ nav ul {
}
nav a {
- color: #fff;
+ color: white;
text-decoration: none;
padding: 0.5em 1em;
}
diff --git a/files/en-us/learn_web_development/core/scripting/dom_scripting/index.md b/files/en-us/learn_web_development/core/scripting/dom_scripting/index.md
index e388d1969573c8d..22338a389d43112 100644
--- a/files/en-us/learn_web_development/core/scripting/dom_scripting/index.md
+++ b/files/en-us/learn_web_development/core/scripting/dom_scripting/index.md
@@ -267,22 +267,23 @@ In the next section we will look at a more practical use of DOM APIs.
## Creating a dynamic shopping list
-In this exercise we want you to build a dynamic shopping list that allows you to add items using a form input and button. When you add an item and press the button:
+In this exercise, we want you to build a dynamic shopping list that allows you to add items using a form input and a button. After you type an item in the input field and click the button or press the Enter key, the following should happen:
- The item should appear in the list.
- Each item should be given a button that can be pressed to delete that item off the list.
-- The input should be emptied and focused, ready for you to enter another item.
+- Each item should have a button next to it that removes the item from the list when clicked.
+- The input fields should be cleared and focused, ready for the next item entry.
The finished demo will look something like the following — try it out before you build it!
```html hidden live-sample___dynamic-shopping-list
My shopping list
-
+
+
```
@@ -303,7 +304,9 @@ const list = document.querySelector("ul");
const input = document.querySelector("input");
const button = document.querySelector("button");
-button.addEventListener("click", () => {
+button.addEventListener("click", (event) => {
+ event.preventDefault();
+
const myItem = input.value;
input.value = "";
@@ -329,17 +332,18 @@ button.addEventListener("click", () => {
To complete the exercise, follow the steps below, and make sure that the list behaves as described above.
-1. To start with, download a copy of our [shopping-list.html](https://github.com/mdn/learning-area/blob/main/javascript/apis/document-manipulation/shopping-list.html) starting file and make a copy of it somewhere. You'll see that it has some minimal CSS, a div with a label, input, and button, and an empty list and {{htmlelement("script")}} element. You'll be making all your additions inside the script.
+1. To begin, download a copy of our [shopping-list.html](https://github.com/mdn/learning-area/blob/main/javascript/apis/document-manipulation/shopping-list.html) starting file and make a copy of it somewhere. You'll see that it has some minimal CSS, a form with a label, input, and button, an empty list, and a {{htmlelement("script")}} element. You'll be making all your additions inside the script.
2. Create three variables that hold references to the list ({{htmlelement("ul")}}), {{htmlelement("input")}}, and {{htmlelement("button")}} elements.
3. Create a [function](/en-US/docs/Learn_web_development/Core/Scripting/Functions) that will run in response to the button being clicked.
-4. Inside the function body, start off by storing the current [value](/en-US/docs/Web/API/HTMLInputElement/value) of the input element in a variable.
-5. Next, empty the input element by setting its value to an empty string — `""`.
-6. Create three new elements — a list item ({{htmlelement('li')}}), {{htmlelement('span')}}, and {{htmlelement('button')}}, and store them in variables.
-7. Append the span and the button as children of the list item.
-8. Set the text content of the span to the input element value you saved earlier, and the text content of the button to 'Delete'.
-9. Append the list item as a child of the list.
-10. Attach an event handler to the delete button so that, when clicked, it will delete the entire list item (`
...
`).
-11. Finally, use the [`focus()`](/en-US/docs/Web/API/HTMLElement/focus) method to focus the input element ready for entering the next shopping list item.
+4. Inside the function body, start by calling [`preventDefault()`](/en-US/docs/Web/API/Event/preventDefault). Since the input is wrapped in a form element, pressing the Enter key will trigger the form to submit. The call to `preventDefault()` will prevent the form from refreshing the page so a new item can be added to the list instead.
+5. Continue by storing the current [value](/en-US/docs/Web/API/HTMLInputElement/value) of the input in a variable.
+6. Next, clear the input element by setting its value to an empty string (`""`).
+7. Create three new elements — a list item ({{htmlelement('li')}}), a {{htmlelement('span')}}, and a {{htmlelement('button')}} — and store them in variables.
+8. Append the span and button as children of the list item.
+9. Set the text content of the span to the input value you saved earlier, and set the text content of the button to `Delete`.
+10. Append the list item to the list.
+11. Attach an event handler to the **Delete** button so that, when clicked, it removes the entire list item (`
...
`).
+12. Finally, use the [`focus()`](/en-US/docs/Web/API/HTMLElement/focus) method to focus the input element, so it's ready for entering the next shopping list item.
## Summary
diff --git a/files/en-us/learn_web_development/core/scripting/image_gallery/index.md b/files/en-us/learn_web_development/core/scripting/image_gallery/index.md
index 024366d26e63e4f..92afa8176369567 100644
--- a/files/en-us/learn_web_development/core/scripting/image_gallery/index.md
+++ b/files/en-us/learn_web_development/core/scripting/image_gallery/index.md
@@ -126,7 +126,7 @@ The images you need to embed in the example and their required `alt` text are as
- [`pic1.jpg`](https://mdn.github.io/shared-assets/images/examples/learn/gallery/pic1.jpg): "Closeup of a human eye".
- [`pic2.jpg`](https://mdn.github.io/shared-assets/images/examples/learn/gallery/pic2.jpg): "Rock that looks like a wave".
- [`pic3.jpg`](https://mdn.github.io/shared-assets/images/examples/learn/gallery/pic3.jpg): "Purple and white pansies".
-- [`pic4.jpg`](https://mdn.github.io/shared-assets/images/examples/learn/gallery/pic4.jpg): "Section of wall from a pharoah's tomb".
+- [`pic4.jpg`](https://mdn.github.io/shared-assets/images/examples/learn/gallery/pic4.jpg): "Section of wall from a pharaoh's tomb".
- [`pic5.jpg`](https://mdn.github.io/shared-assets/images/examples/learn/gallery/pic5.jpg): "Large moth on a leaf".
### Create a data object
@@ -216,9 +216,9 @@ for (const image of images) {
newImage.tabIndex = "0";
// 2f. Append the image as a child of the thumbBar
thumbBar.appendChild(newImage);
- // 2g. Update the display to show the image fullsize when a thumb is clicked
+ // 2g. Update the display to show the image full size when a thumb is clicked
newImage.addEventListener("click", updateDisplayedImage);
- // 2h. Update the display to show the image fullsize when the "Enter" key
+ // 2h. Update the display to show the image full size when the "Enter" key
// is pressed after it has been focused
newImage.addEventListener("keydown", (e) => {
if (e.code === "Enter") {
diff --git a/files/en-us/learn_web_development/extensions/forms/html_forms_in_legacy_browsers/index.md b/files/en-us/learn_web_development/extensions/forms/html_forms_in_legacy_browsers/index.md
index 14675d32d785333..8a2b4c18b3e3242 100644
--- a/files/en-us/learn_web_development/extensions/forms/html_forms_in_legacy_browsers/index.md
+++ b/files/en-us/learn_web_development/extensions/forms/html_forms_in_legacy_browsers/index.md
@@ -116,27 +116,17 @@ The {{cssxref('appearance')}} property can be used to display an element using p
You can use JavaScript to detect whether a particular input type is supported. This is based on the fact we mentioned before — that every input type falls back to `` in non-supporting browsers.
-1. Define a test function. The first line of the function body should create a test `` element:
+Define a test function. The first line of the function body should create a test `` element. Next, set its `type` attribute to the type you want to test. Finally, test the `type` attribute value. In browsers that don't support that input type, the last line will have no effect and the `type` will be returned as `text`. In the below line we are inverting the return value using the negation operator (`!`) because if the `type` isn't `text`, then the type is supported, so we want to return `true`. The complete function looks like this:
- ```js
- function testDatetimeLocalSupport() {
- const testInput = document.createElement("input");
- ```
-
-2. Next, set its `type` attribute to the type you want to test:
-
- ```js-nolint
- testInput.setAttribute("type", "datetime-local");
- ```
-
-3. Now test the `type` attribute value. In browsers that don't support that input type, the last line will have no effect and the `type` will be returned as `text`. In the below line we are inverting the return value using the negation operator (`!`) because if the `type` isn't `text`, then the type is supported, so we want to return `true`:
-
- ```js
- return testInput.type !== "text";
- }
- ```
+```js
+function testDatetimeLocalSupport() {
+ const testInput = document.createElement("input");
+ testInput.setAttribute("type", "datetime-local");
+ return testInput.type !== "text";
+}
+```
-The above example shows the basic idea behind such tests. Instead of reinventing the wheel, however, you should use a feature detection library such as [Modernizr](https://modernizr.com/) to handle such tests.
+The above example shows the basic idea behind such tests. Instead of reinventing the wheel, however, you should use a feature detection library to handle such tests.
Based on the results of that test, you could then for example choose to use JavaScript to build a custom replacement for the non-supported type, or not apply a stylesheet that styles the non-supported type because you want to provide simple default styles to legacy browsers.
diff --git a/files/en-us/learn_web_development/getting_started/your_first_website/publishing_your_website/index.md b/files/en-us/learn_web_development/getting_started/your_first_website/publishing_your_website/index.md
index 18329936f2b04fb..e146b8ef3595d6e 100644
--- a/files/en-us/learn_web_development/getting_started/your_first_website/publishing_your_website/index.md
+++ b/files/en-us/learn_web_development/getting_started/your_first_website/publishing_your_website/index.md
@@ -47,7 +47,7 @@ To have more control over content and website appearance, most professionals/bus
- Web hosting is rented file space on a hosting company's [web server](/en-US/docs/Learn_web_development/Howto/Web_mechanics/What_is_a_web_server). You put website files on the web server. The web server provides website content to website visitors.
- A [domain name](/en-US/docs/Learn_web_development/Howto/Web_mechanics/What_is_a_domain_name) is the unique web address where people find your website, such as `https://www.mozilla.org` or `https://www.bbc.co.uk`. You can rent your domain name for as many years as you want from a **domain registrar**.
-If you get your web hosting _and_ domain name from the same company, they tend to be configured automatically to talk to one another. However, If you get them from separate companies, or want to change your hosting to a different company, you need to do a bit of setup to point the domain name to the correct server. This is so that people will see your website when they navigate to that web address. This is usually done by logging into your domain registrar's website, and setting your domain's [nameservers](https://kinsta.com/knowledgebase/what-is-a-nameserver/) to the ones provided by your hosting company.
+If you get your web hosting _and_ domain name from the same company, they tend to be configured automatically to talk to one another. However, If you get them from separate companies, or want to change your hosting to a different company, you need to do a bit of setup to point the domain name to the correct server. This is so that people will see your website when they navigate to that web address. This is usually done by logging into your domain registrar's website, and setting your domain's [nameservers](https://kinsta.com/blog/what-is-a-nameserver/) to the ones provided by your hosting company.
Companies use various mechanisms to transfer files to their web servers. Many will have more than one option; typical options include:
diff --git a/files/en-us/web/api/canvasrenderingcontext2d/arcto/index.md b/files/en-us/web/api/canvasrenderingcontext2d/arcto/index.md
index 22227bef059c87c..af212b30d320543 100644
--- a/files/en-us/web/api/canvasrenderingcontext2d/arcto/index.md
+++ b/files/en-us/web/api/canvasrenderingcontext2d/arcto/index.md
@@ -325,6 +325,282 @@ class Math2D {
}
} /* end of class Math2D */
+/* Find the geometry that arcTo() uses to draw the path */
+function findConstruction([P0, P1, P2], r, canvasSize, errorTolCenter) {
+ /* Find the center of a circle of radius r having a point T with a
+ * tangent in the direction d and the center on the same side of
+ * the tangent as dirTan. */
+ function findCenter(T, d, r, dirTan) {
+ /* Find direction of line normal to tangent line
+ * Taking larger value to avoid division by 0.
+ * a . n = 0. Set smaller component to 1 */
+ const dn =
+ Math.abs(d.x) < Math.abs(d.y)
+ ? Math2D.point(1, -d.x / d.y)
+ : Math2D.point(-d.y / d.x, 1);
+
+ /* The normal may be pointing towards center or away.
+ * Make towards center if not */
+ if (Math2D.dot(dn, dirTan) < 0) {
+ dn.x = -dn.x;
+ dn.y = -dn.y;
+ }
+
+ /* Move a distance of the radius along line Tx + t * dn
+ * to get to the center of the circle */
+ return Math2D.linePointAt(T, r / Math2D.L2(dn), dn);
+ }
+
+ /* Test for coincidence. Note that points will have small integer
+ * coordinates, so there is no issue with checking for exact
+ * equality */
+ const dir1 = Math2D.vector(P0.x - P1.x, P0.y - P1.y); // dir line 1
+ if (dir1.x === 0 && dir1.y === 0) {
+ // P0 and P1 coincident
+ return [false];
+ }
+
+ const dir2 = Math2D.vector(P2.x - P1.x, P2.y - P1.y); // dir of line 2
+ if (dir2.x === 0 && dir2.y === 0) {
+ // P2 and P1 coincident
+ return [false];
+ }
+
+ /* Magnitudes of direction vectors defining lines */
+ const dir1Mag = Math2D.L2(dir1);
+ const dir2Mag = Math2D.L2(dir2);
+
+ /* Make direction vectors unit length */
+ const dir1_unit = Math2D.vector(dir1.x / dir1Mag, dir1.y / dir1Mag);
+ const dir2_unit = Math2D.vector(dir2.x / dir2Mag, dir2.y / dir2Mag);
+
+ /* Angle between lines -- cos angle = a.b/(|a||b|)
+ * Using unit vectors, so |a| = |b| = 1 */
+ const dp = Math2D.dot(dir1_unit, dir2_unit);
+ /* Test for collinearity */
+ if (Math.abs(dp) > 0.999999) {
+ /* Angle 0 or 180 degrees, or nearly so */
+ return [false];
+ }
+ const angle = Math.acos(Math2D.dot(dir1_unit, dir2_unit));
+
+ /* Distance to tangent points from P1 --
+ * (T1, P1, C) form a right triangle (T2, P1, C) same triangle.
+ * An angle of each triangle is half of the angle between the lines
+ * tan(angle/2) = r / length(P1,T1) */
+ const distToTangent = r / Math.tan(0.5 * angle);
+
+ /* Locate tangent points */
+ const T1 = Math2D.linePointAt(P1, distToTangent, dir1_unit);
+ const T2 = Math2D.linePointAt(P1, distToTangent, dir2_unit);
+
+ /* Center is along normal to tangent at tangent point at
+ * a distance equal to the radius of the circle.
+ * Locate center two ways. Should be equal */
+ const dirT2_T1 = Math2D.vector(T2.x - T1.x, T2.y - T1.y);
+ const dirT1_T2 = Math2D.vector(-dirT2_T1.x, -dirT2_T1.y);
+ const C1 = findCenter(T1, dir1_unit, r, dirT2_T1);
+ const C2 = findCenter(T2, dir2_unit, r, dirT1_T2);
+
+ /* Error in center calculations */
+ const deltaC = Math2D.vector(C2.x - C1.x, C2.y - C1.y);
+ if (deltaC.x * deltaC.x + deltaC.y * deltaC.y > errorTolCenter) {
+ console.error(
+ `Programming or numerical error, ` +
+ `P0(${P0.x},${P0.y}); ` +
+ `P1(${P1.x},${P1.y}); ` +
+ `P2(${P2.x},${P2.y}); ` +
+ `r=${r};`,
+ );
+ }
+
+ /* 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.
+ * 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
+ * being easily found. */
+ const distToInf = canvasSize.x + canvasSize.y;
+ const L1inf = Math2D.linePointAt(P1, distToInf, dir1_unit);
+ const L2inf = Math2D.linePointAt(P1, distToInf, dir2_unit);
+
+ return [true, L1inf, L2inf, T1, T2, C];
+} /* end of function findConstruction */
+
+/* Given configuration parameters, initialize the state */
+function initDemoState({
+ canvasWidth = 300,
+ canvasHeight = 300,
+ hitDistance = 5,
+ errorTolCenter = 1e-4,
+ radiusMax = 250,
+ P0x = 0,
+ P0y = 0,
+ P1x = 0,
+ P1y = 0,
+ P2x = 0,
+ P2y = 0,
+ radius = 0,
+} = {}) {
+ const s = {};
+ s.controlPoints = [
+ Math2D.point(P0x, P0y),
+ Math2D.point(P1x, P1y),
+ Math2D.point(P2x, P2y),
+ ];
+ s.hitDistance = hitDistance;
+ s.errorTolCenter = errorTolCenter;
+ s.canvasSize = Math2D.point(canvasWidth, canvasHeight);
+
+ if (radius > radiusMax) {
+ /* limit param to allowed values */
+ radius = radiusMax;
+ }
+ s.radius = radius;
+ s.radiusMax = radiusMax;
+
+ [s.haveCircle, s.P0Inf, s.P2Inf, s.T1, s.T2, s.C] = findConstruction(
+ s.controlPoints,
+ s.radius,
+ s.canvasSize,
+ s.errorTolCenter,
+ );
+ s.pointActiveIndex = -1; // No point currently active
+ s.pointActiveMoving = false; // Active point hovering (false) or
+ // moving (true)
+ // offset of mouse pointer
+ // from point center
+ s.mouseDelta = Math2D.point();
+ return s;
+}
+
+/* Set initial state based on parameters */
+const state = initDemoState(param);
+
+/* Canvas setup */
+const canvas = document.getElementById("canvas");
+const ctx = canvas.getContext("2d");
+canvas.width = state.canvasSize.x;
+canvas.height = state.canvasSize.y;
+
+class ConstructionPoints {
+ static #vT1 = document.getElementById("value-T1");
+ static #vT2 = document.getElementById("value-T2");
+ static #vC = document.getElementById("value-C");
+ static print(T1, T2, C) {
+ function prettyPoint(P) {
+ return `(${P.x}, ${P.y})`;
+ }
+ if (state.haveCircle) {
+ this.#vT1.textContent = prettyPoint(T1);
+ this.#vT2.textContent = prettyPoint(T2);
+ this.#vC.textContent = prettyPoint(C);
+ } else {
+ this.#vT1.textContent = "undefined";
+ this.#vT2.textContent = "undefined";
+ this.#vC.textContent = "undefined";
+ }
+ }
+}
+
+function updateConstruction() {
+ [state.haveCircle, state.P0Inf, state.P2Inf, state.T1, state.T2, state.C] =
+ findConstruction(
+ state.controlPoints,
+ state.radius,
+ state.canvasSize,
+ state.errorTolCenter,
+ );
+}
+
+function drawCanvas() {
+ const rPoint = 4;
+ const colorConstruction = "green";
+ const colorDraggable = "blue";
+ const [P0, P1, P2] = state.controlPoints;
+
+ ctx.font = "italic 14pt sans-serif";
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ ctx.lineWidth = 1;
+
+ /* Draw construction information if present */
+ if (state.haveCircle) {
+ ctx.strokeStyle = colorConstruction;
+ ctx.fillStyle = colorConstruction;
+ ctx.setLineDash([4, 6]);
+
+ /* Draw the construction points */
+ const specialPoints = [state.C, state.T1, state.T2];
+ specialPoints.forEach((value) => {
+ ctx.beginPath();
+ ctx.arc(value.x, value.y, rPoint, 0, 2 * Math.PI);
+ ctx.fill();
+ });
+
+ /* Draw the semi-infinite lines, a radius, and the circle */
+ ctx.beginPath();
+ ctx.moveTo(state.P0Inf.x, state.P0Inf.y);
+ ctx.lineTo(P1.x, P1.y);
+ ctx.lineTo(state.P2Inf.x, state.P2Inf.y);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(state.C.x, state.C.y);
+ ctx.lineTo(state.T1.x, state.T1.y);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(state.C.x, state.C.y, state.radius, 0, 2 * Math.PI);
+ ctx.stroke();
+
+ ctx.fillStyle = "black";
+ ctx.fillText("C", state.C.x, state.C.y - 15);
+ ctx.fillText("T\u2081", state.T1.x, state.T1.y - 15);
+ ctx.fillText("T\u2082", state.T2.x, state.T2.y - 15);
+ ctx.fillText(
+ " r",
+ 0.5 * (state.T1.x + state.C.x),
+ 0.5 * (state.T1.y + state.C.y),
+ );
+ } else {
+ // no circle
+ ctx.beginPath();
+ ctx.moveTo(P0.x, P0.y);
+ ctx.setLineDash([2, 6]);
+ ctx.lineTo(P1.x, P1.y);
+ ctx.lineTo(P2.x, P2.y);
+ ctx.strokeStyle = colorConstruction;
+ ctx.stroke();
+ }
+
+ /* Draw initial point and control points */
+ state.controlPoints.forEach((value) => {
+ ctx.beginPath();
+ ctx.arc(value.x, value.y, rPoint, 0, 2 * Math.PI);
+ ctx.fillStyle = colorDraggable;
+ ctx.fill();
+ });
+ ctx.fillStyle = "black";
+ ctx.fillText("P\u2080", P0.x, P0.y - 15);
+ ctx.fillText("P\u2081", P1.x, P1.y - 15);
+ ctx.fillText("P\u2082", P2.x, P2.y - 15);
+
+ /* Draw the arcTo() result */
+ ctx.lineWidth = 3;
+ ctx.beginPath();
+ ctx.moveTo(P0.x, P0.y);
+ ctx.setLineDash([]);
+ ctx.arcTo(P1.x, P1.y, P2.x, P2.y, state.radius);
+ ctx.strokeStyle = "black";
+ ctx.stroke();
+} /* end of function drawCanvas */
+
+function updateResults() {
+ updateConstruction();
+ drawCanvas();
+ ConstructionPoints.print(state.T1, state.T2, state.C);
+}
+
/* Text values allowing alternate inputs */
class TextInput {
#valueMax;
@@ -457,172 +733,58 @@ class TextInput {
}
} /* end of class TextInput */
-/* Given configuration parameters, initialize the state */
-function initDemoState({
- canvasWidth = 300,
- canvasHeight = 300,
- hitDistance = 5,
- errorTolCenter = 1e-4,
- radiusMax = 250,
- P0x = 0,
- P0y = 0,
- P1x = 0,
- P1y = 0,
- P2x = 0,
- P2y = 0,
- radius = 0,
-} = {}) {
- const s = {};
- s.controlPoints = [
- Math2D.point(P0x, P0y),
- Math2D.point(P1x, P1y),
- Math2D.point(P2x, P2y),
- ];
- s.hitDistance = hitDistance;
- s.errorTolCenter = errorTolCenter;
- s.canvasSize = Math2D.point(canvasWidth, canvasHeight);
-
- if (radius > radiusMax) {
- /* limit param to allowed values */
- radius = radiusMax;
- }
- s.radius = radius;
- s.radiusMax = radiusMax;
-
- [s.haveCircle, s.P0Inf, s.P2Inf, s.T1, s.T2, s.C] = findConstruction(
- s.controlPoints,
- s.radius,
- s.canvasSize,
- s.errorTolCenter,
- );
- s.pointActiveIndex = -1; // No point currently active
- s.pointActiveMoving = false; // Active point hovering (false) or
- // moving (true)
- // offset of mouse pointer
- // from point center
- s.mouseDelta = Math2D.point();
- return s;
-}
-
-function updateResults() {
- updateConstruction();
- drawCanvas();
- ConstructionPoints.print(state.T1, state.T2, state.C);
-}
-
-function updateConstruction() {
- [state.haveCircle, state.P0Inf, state.P2Inf, state.T1, state.T2, state.C] =
- findConstruction(
- state.controlPoints,
- state.radius,
- state.canvasSize,
- state.errorTolCenter,
- );
-}
-
-/* Find the geometry that arcTo() uses to draw the path */
-function findConstruction([P0, P1, P2], r, canvasSize, errorTolCenter) {
- /* Find the center of a circle of radius r having a point T with a
- * tangent in the direction d and the center on the same side of
- * the tangent as dirTan. */
- function findCenter(T, d, r, dirTan) {
- /* Find direction of line normal to tangent line
- * Taking larger value to avoid division by 0.
- * a . n = 0. Set smaller component to 1 */
- const dn =
- Math.abs(d.x) < Math.abs(d.y)
- ? Math2D.point(1, -d.x / d.y)
- : Math2D.point(-d.y / d.x, 1);
-
- /* The normal may be pointing towards center or away.
- * Make towards center if not */
- if (Math2D.dot(dn, dirTan) < 0) {
- dn.x = -dn.x;
- dn.y = -dn.y;
- }
-
- /* Move a distance of the radius along line Tx + t * dn
- * to get to the center of the circle */
- return Math2D.linePointAt(T, r / Math2D.L2(dn), dn);
- }
-
- /* Test for coincidence. Note that points will have small integer
- * coordinates, so there is no issue with checking for exact
- * equality */
- const dir1 = Math2D.vector(P0.x - P1.x, P0.y - P1.y); // dir line 1
- if (dir1.x === 0 && dir1.y === 0) {
- // P0 and P1 coincident
- return [false];
- }
-
- const dir2 = Math2D.vector(P2.x - P1.x, P2.y - P1.y); // dir of line 2
- if (dir2.x === 0 && dir2.y === 0) {
- // P2 and P1 coincident
- return [false];
- }
-
- /* Magnitudes of direction vectors defining lines */
- const dir1Mag = Math2D.L2(dir1);
- const dir2Mag = Math2D.L2(dir2);
-
- /* Make direction vectors unit length */
- const dir1_unit = Math2D.vector(dir1.x / dir1Mag, dir1.y / dir1Mag);
- const dir2_unit = Math2D.vector(dir2.x / dir2Mag, dir2.y / dir2Mag);
-
- /* Angle between lines -- cos angle = a.b/(|a||b|)
- * Using unit vectors, so |a| = |b| = 1 */
- const dp = Math2D.dot(dir1_unit, dir2_unit);
- /* Test for collinearity */
- if (Math.abs(dp) > 0.999999) {
- /* Angle 0 or 180 degrees, or nearly so */
- return [false];
- }
- const angle = Math.acos(Math2D.dot(dir1_unit, dir2_unit));
-
- /* Distance to tangent points from P1 --
- * (T1, P1, C) form a right triangle (T2, P1, C) same triangle.
- * An angle of each triangle is half of the angle between the lines
- * tan(angle/2) = r / length(P1,T1) */
- const distToTangent = r / Math.tan(0.5 * angle);
-
- /* Locate tangent points */
- const T1 = Math2D.linePointAt(P1, distToTangent, dir1_unit);
- const T2 = Math2D.linePointAt(P1, distToTangent, dir2_unit);
-
- /* Center is along normal to tangent at tangent point at
- * a distance equal to the radius of the circle.
- * Locate center two ways. Should be equal */
- const dirT2_T1 = Math2D.vector(T2.x - T1.x, T2.y - T1.y);
- const dirT1_T2 = Math2D.vector(-dirT2_T1.x, -dirT2_T1.y);
- const C1 = findCenter(T1, dir1_unit, r, dirT2_T1);
- const C2 = findCenter(T2, dir2_unit, r, dirT1_T2);
-
- /* Error in center calculations */
- const deltaC = Math2D.vector(C2.x - C1.x, C2.y - C1.y);
- if (deltaC.x * deltaC.x + deltaC.y * deltaC.y > errorTolCenter) {
- console.error(
- `Programming or numerical error, ` +
- `P0(${P0.x},${P0.y}); ` +
- `P1(${P1.x},${P1.y}); ` +
- `P2(${P2.x},${P2.y}); ` +
- `r=${r};`,
- );
- }
-
- /* 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.
- * 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
- * being easily found. */
- const distToInf = canvasSize.x + canvasSize.y;
- const L1inf = Math2D.linePointAt(P1, distToInf, dir1_unit);
- const L2inf = Math2D.linePointAt(P1, distToInf, dir2_unit);
-
- return [true, L1inf, L2inf, T1, T2, C];
-} /* end of function findConstruction */
+/* Create text inputs to set point locations and arc radius */
+const textInputs = [
+ new TextInput(
+ "value-r",
+ "radius-slider",
+ state.radiusMax,
+ () => state.radius,
+ (value) => (state.radius = value),
+ ),
+ new TextInput(
+ "value-P0x",
+ null,
+ state.canvasSize.x,
+ () => state.controlPoints[0].x,
+ (value) => (state.controlPoints[0].x = value),
+ ),
+ new TextInput(
+ "value-P0y",
+ null,
+ state.canvasSize.y,
+ () => state.controlPoints[0].y,
+ (value) => (state.controlPoints[0].y = value),
+ ),
+ new TextInput(
+ "value-P1x",
+ null,
+ state.canvasSize.x,
+ () => state.controlPoints[1].x,
+ (value) => (state.controlPoints[1].x = value),
+ ),
+ new TextInput(
+ "value-P1y",
+ null,
+ state.canvasSize.y,
+ () => state.controlPoints[1].y,
+ (value) => (state.controlPoints[1].y = value),
+ ),
+ new TextInput(
+ "value-P2x",
+ null,
+ state.canvasSize.x,
+ () => state.controlPoints[2].x,
+ (value) => (state.controlPoints[2].x = value),
+ ),
+ new TextInput(
+ "value-P2y",
+ null,
+ state.canvasSize.y,
+ () => state.controlPoints[2].y,
+ (value) => (state.controlPoints[2].y = value),
+ ),
+];
/* Finds index and distance delta of first point in an array that is
* closest to the specified point or returns index of -1 if none */
@@ -638,54 +800,6 @@ function hitTestPoints(pointAt, points, hitDistance) {
return [-1]; // no hit
}
-/* Handle a mouse move for either a mousemove event or mouseenter */
-function doMouseMove(pointCursor, rBtnDown) {
- /* Test for active move. If so, move accordingly based on the
- * cursor position. The right button down flag handles the case
- * where the cursor leaves the canvas with the right button down
- * and enters with it up (not moving) or down (moving). It
- * also helps to handle unreliable delivery of mouse events. */
- if (state.pointActiveIndex >= 0 && state.pointActiveMoving && rBtnDown) {
- /* A point was moving and is moving more */
- moveActivePointAndUpdate(pointCursor);
- return;
- }
-
- /* If there is not an active move with the right button down,
- * update active state based on hit testing. Mouse events have
- * been found to not be reliably delivered sometimes, particularly
- * with Chrome, so the programming must handle this issue */
- state.pointActiveMoving = false; // not moving
-
- const [pointHitIndex, testDelta] = hitTestPoints(
- pointCursor,
- state.controlPoints,
- state.hitDistance,
- );
- state.pointActiveIndex = pointHitIndex;
- canvas.style.cursor = pointHitIndex < 0 ? "auto" : "pointer";
-}
-
-class ConstructionPoints {
- static #vT1 = document.getElementById("value-T1");
- static #vT2 = document.getElementById("value-T2");
- static #vC = document.getElementById("value-C");
- static print(T1, T2, C) {
- function prettyPoint(P) {
- return `(${P.x}, ${P.y})`;
- }
- if (state.haveCircle) {
- this.#vT1.textContent = prettyPoint(T1);
- this.#vT2.textContent = prettyPoint(T2);
- this.#vC.textContent = prettyPoint(C);
- } else {
- this.#vT1.textContent = "undefined";
- this.#vT2.textContent = "undefined";
- this.#vC.textContent = "undefined";
- }
- }
-}
-
/* Move the active point, which must exist when called, to
* its new point based on the cursor location and the offset of
* the cursor to the center of the point */
@@ -727,88 +841,32 @@ function moveActivePointAndUpdate(pointCursor) {
}
}
-function drawCanvas() {
- const rPoint = 4;
- const colorConstruction = "green";
- const colorDraggable = "blue";
- const [P0, P1, P2] = state.controlPoints;
-
- ctx.font = "italic 14pt sans-serif";
- ctx.clearRect(0, 0, canvas.width, canvas.height);
- ctx.lineWidth = 1;
-
- /* Draw construction information if present */
- if (state.haveCircle) {
- ctx.strokeStyle = colorConstruction;
- ctx.fillStyle = colorConstruction;
- ctx.setLineDash([4, 6]);
-
- /* Draw the construction points */
- const specialPoints = [state.C, state.T1, state.T2];
- specialPoints.forEach((value) => {
- ctx.beginPath();
- ctx.arc(value.x, value.y, rPoint, 0, 2 * Math.PI);
- ctx.fill();
- });
-
- /* Draw the semi-infinite lines, a radius, and the circle */
- ctx.beginPath();
- ctx.moveTo(state.P0Inf.x, state.P0Inf.y);
- ctx.lineTo(P1.x, P1.y);
- ctx.lineTo(state.P2Inf.x, state.P2Inf.y);
- ctx.stroke();
- ctx.beginPath();
- ctx.moveTo(state.C.x, state.C.y);
- ctx.lineTo(state.T1.x, state.T1.y);
- ctx.stroke();
- ctx.beginPath();
- ctx.arc(state.C.x, state.C.y, state.radius, 0, 2 * Math.PI);
- ctx.stroke();
-
- ctx.fillStyle = "black";
- ctx.fillText("C", state.C.x, state.C.y - 15);
- ctx.fillText("T\u2081", state.T1.x, state.T1.y - 15);
- ctx.fillText("T\u2082", state.T2.x, state.T2.y - 15);
- ctx.fillText(
- " r",
- 0.5 * (state.T1.x + state.C.x),
- 0.5 * (state.T1.y + state.C.y),
- );
- } else {
- // no circle
- ctx.beginPath();
- ctx.moveTo(P0.x, P0.y);
- ctx.setLineDash([2, 6]);
- ctx.lineTo(P1.x, P1.y);
- ctx.lineTo(P2.x, P2.y);
- ctx.strokeStyle = colorConstruction;
- ctx.stroke();
+/* Handle a mouse move for either a mousemove event or mouseenter */
+function doMouseMove(pointCursor, rBtnDown) {
+ /* Test for active move. If so, move accordingly based on the
+ * cursor position. The right button down flag handles the case
+ * where the cursor leaves the canvas with the right button down
+ * and enters with it up (not moving) or down (moving). It
+ * also helps to handle unreliable delivery of mouse events. */
+ if (state.pointActiveIndex >= 0 && state.pointActiveMoving && rBtnDown) {
+ /* A point was moving and is moving more */
+ moveActivePointAndUpdate(pointCursor);
+ return;
}
- /* Draw initial point and control points */
- state.controlPoints.forEach((value) => {
- ctx.beginPath();
- ctx.arc(value.x, value.y, rPoint, 0, 2 * Math.PI);
- ctx.fillStyle = colorDraggable;
- ctx.fill();
- });
- ctx.fillStyle = "black";
- ctx.fillText("P\u2080", P0.x, P0.y - 15);
- ctx.fillText("P\u2081", P1.x, P1.y - 15);
- ctx.fillText("P\u2082", P2.x, P2.y - 15);
-
- /* Draw the arcTo() result */
- ctx.lineWidth = 3;
- ctx.beginPath();
- ctx.moveTo(P0.x, P0.y);
- ctx.setLineDash([]);
- ctx.arcTo(P1.x, P1.y, P2.x, P2.y, state.radius);
- ctx.strokeStyle = "black";
- ctx.stroke();
-} /* end of function drawCanvas */
+ /* If there is not an active move with the right button down,
+ * update active state based on hit testing. Mouse events have
+ * been found to not be reliably delivered sometimes, particularly
+ * with Chrome, so the programming must handle this issue */
+ state.pointActiveMoving = false; // not moving
-function addPointArrowMoves() {
- [0, 1, 2].forEach((value) => addPointArrowMove(value));
+ const [pointHitIndex, testDelta] = hitTestPoints(
+ pointCursor,
+ state.controlPoints,
+ state.hitDistance,
+ );
+ state.pointActiveIndex = pointHitIndex;
+ canvas.style.cursor = pointHitIndex < 0 ? "auto" : "pointer";
}
/* Allow arrow key presses on the point labels to move the point in
@@ -844,8 +902,9 @@ function addPointArrowMove(indexPoint) {
});
}
-/* Set initial state based on parameters */
-const state = initDemoState(param);
+function addPointArrowMoves() {
+ [0, 1, 2].forEach((value) => addPointArrowMove(value));
+}
/* Radius slider update */
const controlR = document.getElementById("radius-slider");
@@ -857,71 +916,12 @@ controlR.addEventListener("input", (evt) => {
updateResults();
});
-/* Create text inputs to set point locations and arc radius */
-const textInputs = [
- new TextInput(
- "value-r",
- "radius-slider",
- state.radiusMax,
- () => state.radius,
- (value) => (state.radius = value),
- ),
- new TextInput(
- "value-P0x",
- null,
- state.canvasSize.x,
- () => state.controlPoints[0].x,
- (value) => (state.controlPoints[0].x = value),
- ),
- new TextInput(
- "value-P0y",
- null,
- state.canvasSize.y,
- () => state.controlPoints[0].y,
- (value) => (state.controlPoints[0].y = value),
- ),
- new TextInput(
- "value-P1x",
- null,
- state.canvasSize.x,
- () => state.controlPoints[1].x,
- (value) => (state.controlPoints[1].x = value),
- ),
- new TextInput(
- "value-P1y",
- null,
- state.canvasSize.y,
- () => state.controlPoints[1].y,
- (value) => (state.controlPoints[1].y = value),
- ),
- new TextInput(
- "value-P2x",
- null,
- state.canvasSize.x,
- () => state.controlPoints[2].x,
- (value) => (state.controlPoints[2].x = value),
- ),
- new TextInput(
- "value-P2y",
- null,
- state.canvasSize.y,
- () => state.controlPoints[2].y,
- (value) => (state.controlPoints[2].y = value),
- ),
-];
-
/* Allow arrow keystrokes to alter point location */
addPointArrowMoves();
/* Initialize the text inputs from the associated state values */
textInputs.forEach((ti) => (ti.elementText.textContent = ti.getStateValue()));
-/* Canvas setup */
-const canvas = document.getElementById("canvas");
-const ctx = canvas.getContext("2d");
-canvas.width = state.canvasSize.x;
-canvas.height = state.canvasSize.y;
-
/* Mouse may move a moving point, move over and hover an unhovered
* point, move across a hovered point, or move on other parts of
* the canvas */
diff --git a/files/en-us/web/api/canvasrenderingcontext2d/globalcompositeoperation/index.md b/files/en-us/web/api/canvasrenderingcontext2d/globalcompositeoperation/index.md
index b9033553effc83e..0e9003e738926ac 100644
--- a/files/en-us/web/api/canvasrenderingcontext2d/globalcompositeoperation/index.md
+++ b/files/en-us/web/api/canvasrenderingcontext2d/globalcompositeoperation/index.md
@@ -190,9 +190,9 @@ canvas2.height = height;
This code, `runComposite()`, handles the bulk of the work, relying on a number of utility functions to do the hard parts.
```js
-function createCanvas() {
+function createCanvas(op) {
const canvas = document.createElement("canvas");
- canvas.style.background = `url(${JSON.stringify(op_8x8.data)})`;
+ canvas.style.background = `url(${JSON.stringify(op.data)})`;
canvas.style.border = "1px solid black";
canvas.style.margin = "5px";
canvas.width = width / 2;
@@ -200,7 +200,7 @@ function createCanvas() {
return canvas;
}
-function runComposite() {
+function runComposite(op) {
const dl = document.createElement("dl");
document.body.appendChild(dl);
while (gco.length) {
@@ -213,9 +213,9 @@ function runComposite() {
p.textContent = gcoText.pop();
dd.appendChild(p);
- const canvasToDrawOn = createCanvas();
- const canvasToDrawFrom = createCanvas();
- const canvasToDrawResult = createCanvas();
+ const canvasToDrawOn = createCanvas(op);
+ const canvasToDrawFrom = createCanvas(op);
+ const canvasToDrawResult = createCanvas(op);
let ctx = canvasToDrawResult.getContext("2d");
ctx.clearRect(0, 0, width, height);
@@ -292,7 +292,7 @@ function lightMix() {
```
```js
-function colorSphere(element) {
+function colorSphere() {
const ctx = canvas1.getContext("2d");
const width = 360;
const halfWidth = width / 2;
@@ -411,7 +411,7 @@ Finally, we call the functions to set everything in motion.
```js
lightMix();
colorSphere();
-runComposite();
+runComposite(op_8x8);
```
#### Result
diff --git a/files/en-us/web/api/htmlvideoelement/cancelvideoframecallback/index.md b/files/en-us/web/api/htmlvideoelement/cancelvideoframecallback/index.md
index d7ff37413b71c5c..4d8bafef555cdfe 100644
--- a/files/en-us/web/api/htmlvideoelement/cancelvideoframecallback/index.md
+++ b/files/en-us/web/api/htmlvideoelement/cancelvideoframecallback/index.md
@@ -32,10 +32,9 @@ None ({{jsxref("undefined")}}).
This example shows how to use `cancelVideoFrameCallback()` to cancel a previously-registered video frame callback.
```js
-// Initial registration of the callback to run on the first frame
-let videoCallbackId = video.requestVideoFrameCallback(updateCanvas);
+let videoCallbackId = null;
-const updateCanvas = (now, metadata) => {
+function updateCanvas(now, metadata) {
// Do something with the frame
// …
@@ -44,12 +43,17 @@ const updateCanvas = (now, metadata) => {
// It's important to update the videoCallbackId on each iteration
// so you can cancel the callback successfully
videoCallbackId = video.requestVideoFrameCallback(updateCanvas);
-};
+}
+
+// Initial registration of the callback to run on the first frame
+videoCallbackId = video.requestVideoFrameCallback(updateCanvas);
// …
// Cancel video frame callback using the latest videoCallbackId
-video.cancelVideoFrameCallback(videoCallbackId);
+if (videoCallbackId !== null) {
+ video.cancelVideoFrameCallback(videoCallbackId);
+}
```
## Specifications
diff --git a/files/en-us/web/api/speechrecognition/available_static/index.md b/files/en-us/web/api/speechrecognition/available_static/index.md
index 6a53fc0aebb1fdd..70a458c931b53fe 100644
--- a/files/en-us/web/api/speechrecognition/available_static/index.md
+++ b/files/en-us/web/api/speechrecognition/available_static/index.md
@@ -3,7 +3,7 @@ title: "SpeechRecognition: available() static method"
short-title: available()
slug: Web/API/SpeechRecognition/available_static
page-type: web-api-static-method
-browser-compat: api.SpeechRecognition.available
+browser-compat: api.SpeechRecognition.available_static
---
{{APIRef("Web Speech API")}}
diff --git a/files/en-us/web/api/speechrecognition/install_static/index.md b/files/en-us/web/api/speechrecognition/install_static/index.md
index c8f3675880d8cb0..716f82a80cd82d0 100644
--- a/files/en-us/web/api/speechrecognition/install_static/index.md
+++ b/files/en-us/web/api/speechrecognition/install_static/index.md
@@ -3,7 +3,7 @@ title: "SpeechRecognition: install() static method"
short-title: install()
slug: Web/API/SpeechRecognition/install_static
page-type: web-api-static-method
-browser-compat: api.SpeechRecognition.install
+browser-compat: api.SpeechRecognition.install_static
---
{{APIRef("Web Speech API")}}
diff --git a/files/en-us/web/api/web_speech_api/using_the_web_speech_api/index.md b/files/en-us/web/api/web_speech_api/using_the_web_speech_api/index.md
index 8e3b3283d831045..9bfb71d2c72f2b1 100644
--- a/files/en-us/web/api/web_speech_api/using_the_web_speech_api/index.md
+++ b/files/en-us/web/api/web_speech_api/using_the_web_speech_api/index.md
@@ -260,9 +260,9 @@ In the on-device version of the demo, prefix-handling code is not needed because
## Contextual biasing in speech recognition
-There will be times when a speech recognition service will fail to correctly recognize a specific word or phrase. This most often happens with domain-specific terms (such as medical or scientific vocabulary), proper nouns, uncommon phrases, or words that sound similar to other words and so may be misrecognized.
+There will be times when a speech recognition service will fail to correctly recognize a specific word or phrase. This most often happens with domain-specific terms (such as medical or scientific vocabulary), proper nouns, uncommon phrases, or words that sound similar to other words and so may be misidentified.
-For example, during testing, we found that our [On-device speech color changer](https://mdn.github.io/dom-examples/web-speech-api/speech-color-changer/) had trouble recognizing the color `azure` — it kept returning results like "as you". Other colors that were frequently misrecognized included `khaki` ("car key"), `tan`, and `thistle` ("this all").
+For example, during testing, we found that our [On-device speech color changer](https://mdn.github.io/dom-examples/web-speech-api/speech-color-changer/) had trouble recognizing the color `azure` — it kept returning results like "as you". Other colors that were frequently misidentified included `khaki` ("car key"), `tan`, and `thistle` ("this all").
To mitigate such problems, the Web Speech API lets you provide hints to the recognition engine to highlight phrases that are more likely to be spoken and which the engine should be biased towards. This makes those words and phrases more likely to be recognized correctly.
@@ -311,7 +311,7 @@ The Web Speech API has a main controller interface for this — {{domxref("Speec
### Demo
-To demonstrate how to use web speech synthesis, we've created a sample app called [Speech synthesiser](https://github.com/mdn/dom-examples/tree/main/web-speech-api/speak-easy-synthesis). It has an input field for entering the text to be synthesized. You can adjust the rate and pitch and also select a voice from the dropdown menu to use for the spoken text. After you've entered your text, press Enter/Return or click the **Play** button to hear the text read aloud.
+To demonstrate how to use web speech synthesis, we've created a sample app called [Speech synthesizer](https://github.com/mdn/dom-examples/tree/main/web-speech-api/speak-easy-synthesis). It has an input field for entering the text to be synthesized. You can adjust the rate and pitch and also select a voice from the dropdown menu to use for the spoken text. After you've entered your text, press Enter/Return or click the **Play** button to hear the text read aloud.

diff --git a/files/en-us/web/api/webgl_api/by_example/raining_rectangles/index.md b/files/en-us/web/api/webgl_api/by_example/raining_rectangles/index.md
index 99545e642781d8d..a659051c6bb5b24 100644
--- a/files/en-us/web/api/webgl_api/by_example/raining_rectangles/index.md
+++ b/files/en-us/web/api/webgl_api/by_example/raining_rectangles/index.md
@@ -48,6 +48,26 @@ button {
```
```js
+const canvas = document.querySelector("canvas");
+const [scoreDisplay, missesDisplay] = document.querySelectorAll("strong");
+
+function getRenderingContext() {
+ canvas.width = canvas.clientWidth;
+ canvas.height = canvas.clientHeight;
+ const gl = canvas.getContext("webgl");
+ gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+ gl.clearColor(0.0, 0.0, 0.0, 1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ return gl;
+}
+
+const gl = getRenderingContext();
+gl.enable(gl.SCISSOR_TEST);
+
+function getRandomVector() {
+ return [Math.random(), Math.random(), Math.random()];
+}
+
class Rectangle {
constructor() {
// We get three random numbers and use them for new rectangle
@@ -66,28 +86,11 @@ class Rectangle {
}
}
-const canvas = document.querySelector("canvas");
-
-const gl = getRenderingContext();
-gl.enable(gl.SCISSOR_TEST);
let rainingRect = new Rectangle();
-let timer = setTimeout(drawAnimation, 17);
-canvas.addEventListener("click", playerClick);
-const [scoreDisplay, missesDisplay] = document.querySelectorAll("strong");
-
-function getRenderingContext() {
- canvas.width = canvas.clientWidth;
- canvas.height = canvas.clientHeight;
- const gl = canvas.getContext("webgl");
- gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
- gl.clearColor(0.0, 0.0, 0.0, 1.0);
- gl.clear(gl.COLOR_BUFFER_BIT);
- return gl;
-}
-
let score = 0;
let misses = 0;
+let timer = null;
function drawAnimation() {
gl.scissor(
rainingRect.position[0],
@@ -137,9 +140,8 @@ function playerClick(evt) {
}
}
-function getRandomVector() {
- return [Math.random(), Math.random(), Math.random()];
-}
+timer = setTimeout(drawAnimation, 17);
+canvas.addEventListener("click", playerClick);
```
The source code of this example is also available on [GitHub](https://github.com/idofilin/webgl-by-example/tree/master/raining-rectangles).
diff --git a/files/en-us/web/api/webgl_api/data/index.md b/files/en-us/web/api/webgl_api/data/index.md
index 8f31455bee805e0..4164cb3575dd143 100644
--- a/files/en-us/web/api/webgl_api/data/index.md
+++ b/files/en-us/web/api/webgl_api/data/index.md
@@ -10,7 +10,7 @@ Shader programs have access to three kinds of data storage, each of which has a
## GLSL data types
-See [Data Types]() in the GLSL documentation.
+See [Data Types]() in the GLSL documentation.
## GLSL variables
diff --git a/files/en-us/web/api/webgl_compressed_texture_s3tc/index.md b/files/en-us/web/api/webgl_compressed_texture_s3tc/index.md
index ff12c6edf14b136..c8ec2a24c82a164 100644
--- a/files/en-us/web/api/webgl_compressed_texture_s3tc/index.md
+++ b/files/en-us/web/api/webgl_compressed_texture_s3tc/index.md
@@ -65,7 +65,7 @@ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
## See also
-- [S3 Texture Compression – OpenGL wiki](https://www.khronos.org/opengl/wiki/S3_Texture_Compression)
+- [S3 Texture Compression – OpenGL wiki](https://wikis.khronos.org/opengl/S3_Texture_Compression)
- {{domxref("WebGLRenderingContext.getExtension()")}}
- {{domxref("WebGLRenderingContext.compressedTexImage2D()")}}
- {{domxref("WebGLRenderingContext.compressedTexSubImage2D()")}}
diff --git a/files/en-us/web/api/webgl_compressed_texture_s3tc_srgb/index.md b/files/en-us/web/api/webgl_compressed_texture_s3tc_srgb/index.md
index af068762ad5c908..49f03728a826e6c 100644
--- a/files/en-us/web/api/webgl_compressed_texture_s3tc_srgb/index.md
+++ b/files/en-us/web/api/webgl_compressed_texture_s3tc_srgb/index.md
@@ -62,7 +62,7 @@ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
## See also
-- [S3 Texture Compression – OpenGL wiki](https://www.khronos.org/opengl/wiki/S3_Texture_Compression#sRGB_and_S3TC)
+- [S3 Texture Compression – OpenGL wiki](https://wikis.khronos.org/opengl/S3_Texture_Compression#sRGB_and_S3TC)
- {{domxref("WebGLRenderingContext.getExtension()")}}
- {{domxref("WebGLRenderingContext.compressedTexImage2D()")}}
- {{domxref("WebGLRenderingContext.compressedTexSubImage2D()")}}
diff --git a/files/en-us/web/api/webglrenderingcontext/iscontextlost/index.md b/files/en-us/web/api/webglrenderingcontext/iscontextlost/index.md
index 1a55dea0a1604f4..276f3015bd35f12 100644
--- a/files/en-us/web/api/webglrenderingcontext/iscontextlost/index.md
+++ b/files/en-us/web/api/webglrenderingcontext/iscontextlost/index.md
@@ -71,4 +71,4 @@ if (!gl.getProgramParameter(program, gl.LINK_STATUS) && !gl.isContextLost()) {
## See also
- The {{domxref("WebGLContextEvent")}} signals changes in the context state.
-- [Handling lost context in WebGL](https://www.khronos.org/webgl/wiki/HandlingContextLost): Khronos WebGL wiki
+- [Handling lost context in WebGL](https://wikis.khronos.org/webgl/HandlingContextLost): Khronos WebGL wiki
diff --git a/files/en-us/web/api/webglrenderingcontext/vertexattribpointer/index.md b/files/en-us/web/api/webglrenderingcontext/vertexattribpointer/index.md
index fdc229c73e70116..a64348fd7c61614 100644
--- a/files/en-us/web/api/webglrenderingcontext/vertexattribpointer/index.md
+++ b/files/en-us/web/api/webglrenderingcontext/vertexattribpointer/index.md
@@ -300,5 +300,5 @@ gl.enableVertexAttribArray(locTexUV);
## See also
-- [Vertex Specification](https://www.khronos.org/opengl/wiki/Vertex_Specification) on the OpenGL wiki
+- [Vertex Specification](https://wikis.khronos.org/opengl/Vertex_Specification) on the OpenGL wiki
- {{domxref("WebGL2RenderingContext.vertexAttribIPointer()")}}
diff --git a/files/en-us/web/api/webgpu_api/index.md b/files/en-us/web/api/webgpu_api/index.md
index a684d7ade312bbd..e9cf222c93aeaa8 100644
--- a/files/en-us/web/api/webgpu_api/index.md
+++ b/files/en-us/web/api/webgpu_api/index.md
@@ -15,7 +15,7 @@ WebGPU is the successor to {{domxref("WebGL_API", "WebGL", "", "nocode")}}, prov
It is fair to say that {{domxref("WebGL_API", "WebGL", "", "nocode")}} revolutionized the web in terms of graphical capabilities after it first appeared around 2011. WebGL is a JavaScript port of the [OpenGL ES 2.0](https://registry.khronos.org/OpenGL-Refpages/es2.0/) graphics library, allowing web pages to pass rendering computations directly to the device's GPU to be processed at very high speeds, and render the result inside a {{htmlelement("canvas")}} element.
-WebGL and the [GLSL]() language used to write WebGL shader code are complex, so several WebGL libraries have been created to make WebGL apps easier to write: Popular examples include [Three.js](https://threejs.org/), [Babylon.js](https://www.babylonjs.com/), and [PlayCanvas](https://playcanvas.com/). Developers have used these tools to build immersive web-based 3D games, music videos, training and modeling tools, VR and AR experiences, and more.
+WebGL and the [GLSL]() language used to write WebGL shader code are complex, so several WebGL libraries have been created to make WebGL apps easier to write: Popular examples include [Three.js](https://threejs.org/), [Babylon.js](https://www.babylonjs.com/), and [PlayCanvas](https://playcanvas.com/). Developers have used these tools to build immersive web-based 3D games, music videos, training and modeling tools, VR and AR experiences, and more.
However, WebGL has some fundamental issues that needed addressing:
diff --git a/files/en-us/web/api/xrwebgllayer/xrwebgllayer/index.md b/files/en-us/web/api/xrwebgllayer/xrwebgllayer/index.md
index 2819399e45dffee..c023b6720e78960 100644
--- a/files/en-us/web/api/xrwebgllayer/xrwebgllayer/index.md
+++ b/files/en-us/web/api/xrwebgllayer/xrwebgllayer/index.md
@@ -97,4 +97,4 @@ xrSession.updateRenderState({
- [WebXR Device API](/en-US/docs/Web/API/WebXR_Device_API)
- [Getting started with WebGL](/en-US/docs/Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL)
-- [Handling lost context in WebGL](https://www.khronos.org/webgl/wiki/HandlingContextLost): Khronos WebGL wiki
+- [Handling lost context in WebGL](https://wikis.khronos.org/webgl/HandlingContextLost): Khronos WebGL wiki
diff --git a/files/en-us/web/css/dynamic-range-limit-mix/index.md b/files/en-us/web/css/dynamic-range-limit-mix/index.md
index 15eef1ff2565e98..bd9306ba3031453 100644
--- a/files/en-us/web/css/dynamic-range-limit-mix/index.md
+++ b/files/en-us/web/css/dynamic-range-limit-mix/index.md
@@ -82,7 +82,7 @@ dynamic-range-limit-mix(
- The first line gives us `no-limit 10%`.
- Since `25%` and `75%` add up to `100%`, the second line gives us `standard 5%` (`25%` of `20%`) and `constrained 15%` (`75%` of `20%`).
-- In the third line, because `10%` and `30%` add up to only `40%`, not `100%`, we normalize both as proportions of `40%`: 10/40=`25%` and 30/40=`75%`. This gives us `constrained 5%` (`25%` of `20%`) and `no-limit 15%` (`75%` of `20%`).
+- In the third line, because `10%` and `30%` add up to only `40%`, not `100%`, we normalize both as proportions of `40%`: 10/40 = `25%` and 30/40 = `75%`. This gives us `constrained 5%` (`25%` of `20%`) and `no-limit 15%` (`75%` of `20%`).
Adding these up to get the raw percentages gives us:
diff --git a/files/en-us/web/javascript/reference/global_objects/intl/supportedvaluesof/index.md b/files/en-us/web/javascript/reference/global_objects/intl/supportedvaluesof/index.md
index baef555193e9415..93d489190c1e247 100644
--- a/files/en-us/web/javascript/reference/global_objects/intl/supportedvaluesof/index.md
+++ b/files/en-us/web/javascript/reference/global_objects/intl/supportedvaluesof/index.md
@@ -72,7 +72,7 @@ Below are all values that are commonly supported by browsers for the `calendar`
| `hebrew` | Traditional Hebrew calendar |
| `indian` | Indian calendar |
| `islamic` | Hijri calendar, unspecified algorithm. **Note:** As of April 2025, this is an astronomical simulation whose parameters are undocumented and that is not known to match a specific Hijri calendar variant from non-software contexts. For well-specified results, use one of the three specific variants: `islamic-umalqura`, `islamic-tbla`, or `islamic-civil`. |
-| `islamic-umalqura` | Hijri calendar, Umm al-Qura (uses KACST-calculated months from the start of 1300 AH to the end of 1600 AH and falls back to `islamic-civil` outside that range) |
+| `islamic-umalqura` | Hijri calendar, Umm al-Qura (uses KACST-calculated months from the start of 1300 AH (1882-11-12 ISO) to the end of 1600 AH (2174-11-25 ISO) and falls back to `islamic-civil` outside that range) |
| `islamic-tbla` | Hijri calendar, tabular/rule-based with leap year rule II (leap years 2,5,7,10,13,16,18,21,24,26,29 in the 30-year cycle (1-based numbering)) and Thursday/astronomical epoch (July 15, 622 Julian / 0622-07-18 ISO) |
| `islamic-civil` | Hijri calendar, tabular/rule-based with leap year rule II (leap years 2,5,7,10,13,16,18,21,24,26,29 in the 30-year cycle (1-based numbering)) and Friday/civil epoch (July 16, 622 Julian / 0622-07-19 ISO) |
| `iso8601` | ISO calendar (variant of the Gregorian calendar with week rules and formatting parameters made region-independent) |
diff --git a/files/en-us/web/media/guides/audio_and_video_delivery/index.md b/files/en-us/web/media/guides/audio_and_video_delivery/index.md
index be548b3e0c0ecf2..2dd986dd36eac86 100644
--- a/files/en-us/web/media/guides/audio_and_video_delivery/index.md
+++ b/files/en-us/web/media/guides/audio_and_video_delivery/index.md
@@ -470,7 +470,7 @@ A number of audio and video JavaScript libraries exist. The most popular librari
- [flowplayer](https://flowplayer.com/): Gratis with a flowplayer logo watermark. Open source (GPL licensed.)
- [JWPlayer](https://jwpconnatix.com/): Requires registration to download. Open Source Edition (Creative Commons License.)
- [SublimeVideo](https://www.sublimevideo.net/): Requires registration. Form based set up with domain specific link to CDN hosted library.
-- [Video.js](https://videojs.com/): Gratis and Open Source (Apache 2 Licensed.)
+- [Video.js](https://videojs.org/): Gratis and Open Source (Apache 2 Licensed.)
### Audio and Video