|
7 | 7 | </head>
|
8 | 8 | <body>
|
9 | 9 | <header>
|
10 |
| - <div id="support-div">Your browser does not support OffscreenCanvas</div> |
11 |
| - </header> |
12 |
| - |
13 |
| - <main> |
14 |
| - <h2>Simulate a heavy process:</h2> |
| 10 | + <h1>OffscreenCanvas and worker threads</h1> |
| 11 | + <p>This example has two canvases with incrementing counters.</p> |
15 | 12 |
|
16 |
| - <button id="main-button" onclick="slowMainThread()">Canvas A</button> |
17 |
| - <button id="worker-button" onclick="slowdownWorker()">Canvas B</button> |
| 13 | + <p> |
| 14 | + Canvas A is being drawn to on the main thread. Canvas B uses an |
| 15 | + OffscreenCanvas so that we can draw to it in a worker thread. The |
| 16 | + purpose of this example is to show how a worker thread can keep the rest |
| 17 | + of our UI responsive. |
| 18 | + </p> |
18 | 19 |
|
19 |
| - <div class="ui-example"> |
20 |
| - <button>Hover example</button><button>Hover example</button |
21 |
| - ><button>Hover example</button><button>Hover example</button> |
22 |
| - </div> |
| 20 | + <p> |
| 21 | + The button below each canvas creates <b>blocking work</b> on either the |
| 22 | + main thread (Canvas A) or a worker thread (Canvas B). When a thread is |
| 23 | + blocked, the canvas' counter in that thread is blocked. |
| 24 | + </p> |
| 25 | + </header> |
23 | 26 |
|
24 |
| - <h2>Counters:</h2> |
25 |
| - <div class="visualisation"> |
| 27 | + <main> |
| 28 | + <div class="canvases"> |
26 | 29 | <div>
|
27 | 30 | <span class="canvas-title">Canvas A</span>
|
28 |
| - <canvas id="canvas main" width="400" height="400"></canvas> |
| 31 | + <canvas id="canvas main" width="200" height="200"></canvas> |
| 32 | + <div> |
| 33 | + <button id="main-button" onclick="slowMainThread()"> |
| 34 | + Main thread |
| 35 | + </button> |
| 36 | + </div> |
29 | 37 | </div>
|
30 | 38 | <div>
|
31 | 39 | <span class="canvas-title">Canvas B</span>
|
32 |
| - <canvas id="canvas worker" width="400" height="400"></canvas> |
| 40 | + <canvas id="canvas worker" width="200" height="200"></canvas> |
| 41 | + |
| 42 | + <div> |
| 43 | + <button id="worker-button" onclick="slowdownWorker()"> |
| 44 | + Worker thread |
| 45 | + </button> |
| 46 | + </div> |
33 | 47 | </div>
|
34 | 48 | </div>
|
| 49 | + <div id="canvas-description"> |
| 50 | + <p> |
| 51 | + <b>When the main thread is blocked</b>, all UI elements are frozen. |
| 52 | + The hover effect on all buttons is affected: |
| 53 | + </p> |
| 54 | + <button>Example button</button> |
| 55 | + <p> |
| 56 | + <b>When the worker thread is blocked</b>, the main thread is free to |
| 57 | + do work such as the element hover effects and animations. Blocking the |
| 58 | + worker thread will still prevent Canvas B's counter from being |
| 59 | + updated, but the UI stays responsive while this happens. |
| 60 | + </p> |
| 61 | + </div> |
35 | 62 | </main>
|
36 | 63 |
|
37 | 64 | <script>
|
38 |
| - document |
39 |
| - .querySelector("#support-div") |
40 |
| - .classList.add( |
41 |
| - "OffscreenCanvas" in window ? "supported" : "not-supported" |
42 |
| - ); |
43 |
| - |
44 |
| - document.querySelector("#support-div").innerHTML = |
45 |
| - "OffscreenCanvas" in window |
46 |
| - ? "Your browser supports the OffscreenCanvas API " |
47 |
| - : "Your browser does not support OffscreenCanvas"; |
48 |
| - |
49 | 65 | const requestAnimationFrame = window.requestAnimationFrame;
|
50 | 66 |
|
51 |
| - // Init Canvas A (running on the current page) |
52 | 67 | const canvasA = document.getElementById("canvas main");
|
53 |
| - const indicator = document.getElementById("indicator"); |
54 |
| - const ctxA = canvasA.getContext("2d"); |
| 68 | + const canvasB = document.getElementById("canvas worker"); |
55 | 69 |
|
| 70 | + const ctxA = canvasA.getContext("2d"); |
56 | 71 | const canvasWidth = ctxA.width;
|
57 | 72 | const canvasHeight = ctxA.height;
|
58 | 73 |
|
59 |
| - // Setup the counter for Canvas A |
| 74 | + // Create a counter for Canvas A |
60 | 75 | let counter = 0;
|
61 | 76 | setInterval(function () {
|
62 | 77 | redrawCanvasA();
|
63 | 78 | counter++;
|
64 | 79 | }, 100);
|
65 | 80 |
|
66 |
| - // Redraw Canvas A text |
| 81 | + // Redraw Canvas A counter |
67 | 82 | function redrawCanvasA() {
|
68 | 83 | ctxA.clearRect(0, 0, canvasA.width, canvasA.height);
|
69 |
| - ctxA.font = "16px Verdana"; |
| 84 | + ctxA.font = "24px Verdana"; |
70 | 85 | ctxA.textAlign = "center";
|
71 |
| - ctxA.fillText( |
72 |
| - "Counter: " + counter, |
73 |
| - canvasA.width / 2, |
74 |
| - canvasA.height / 2 |
75 |
| - ); |
| 86 | + ctxA.fillText(counter, canvasA.width / 2, canvasA.height / 2); |
76 | 87 | }
|
77 | 88 |
|
78 |
| - // Using the OffscreenCanvas API and starting the worker |
79 |
| - var cWorker = document |
80 |
| - .getElementById("canvas worker") |
81 |
| - .transferControlToOffscreen(); |
82 |
| - var worker = new Worker("worker.js"); |
83 |
| - worker.postMessage({ canvas: cWorker }, [cWorker]); |
84 |
| - |
85 |
| - // Fibonacci function to add some delay to the thread |
| 89 | + // This function creates heavy (blocking) work on a thread |
86 | 90 | function fibonacci(num) {
|
87 | 91 | if (num <= 1) return 1;
|
88 | 92 | return fibonacci(num - 1) + fibonacci(num - 2);
|
89 | 93 | }
|
90 | 94 |
|
| 95 | + // Call our Fibonacci function on the main thread |
91 | 96 | function slowMainThread() {
|
92 | 97 | fibonacci(42);
|
93 | 98 | }
|
94 | 99 |
|
95 |
| - // Initiate the slowing down of Canvas B |
96 |
| - // By sending a message to the worker |
| 100 | + // Set up a worker thread to render Canvas B |
| 101 | + const worker = new Worker("worker.js"); |
| 102 | + |
| 103 | + // Use the OffscreenCanvas API and send to the worker thread |
| 104 | + const canvasWorker = canvasB.transferControlToOffscreen(); |
| 105 | + worker.postMessage({ canvas: canvasWorker }, [canvasWorker]); |
| 106 | + |
| 107 | + // A 'slowDown' message we can catch in the worker to start heavy work |
97 | 108 | function slowdownWorker() {
|
98 | 109 | worker.postMessage("slowDown");
|
99 | 110 | }
|
|
0 commit comments