- From: poot <cvsmail@w3.org>
- Date: Thu, 7 Aug 2008 07:11:13 +0900 (JST)
- To: public-html-diffs@w3.org
Add another example. (whatwg r43) 1.1.5 Granting capabilities http://people.w3.org/mike/diffs/html5/workers/Overview.1.36.html#granting 1.1.6 Delegation http://people.w3.org/mike/diffs/html5/workers/Overview.1.36.html#delegation 1.1.4 Shared workers http://people.w3.org/mike/diffs/html5/workers/Overview.1.36.html#shared 1.2 Conformance requirements http://people.w3.org/mike/diffs/html5/workers/Overview.1.36.html#conformance http://people.w3.org/mike/diffs/html5/workers/Overview.diff.html http://dev.w3.org/cvsweb/html5/workers/Overview.html?r1=1.35&r2=1.36&f=h http://html5.org/tools/web-apps-tracker?from=42&to=43 =================================================================== RCS file: /sources/public/html5/workers/Overview.html,v retrieving revision 1.35 retrieving revision 1.36 diff -u -d -r1.35 -r1.36 --- Overview.html 6 Aug 2008 11:26:32 -0000 1.35 +++ Overview.html 6 Aug 2008 22:09:55 -0000 1.36 @@ -480,19 +480,312 @@ port.postMessage(get('search.cgi?' + event.message)); };</pre> - <p><a href="http://www.whatwg.org/demos/workers/stock/page.html">View this + <p><a href="http://www.whatwg.org/demos/workers/stocks/page.html">View this example online</a>. <h4 id=shared><span class=secno>1.1.4 </span>Shared workers</h4> - <p class=big-issue>... + <p><em>This section is non-normative.</em> + + <p>In this example, multiple windows (viewers) can be opened that are all + viewing the same map. All the windows share the same map information, with + a single worker coordinating all the viewers. Each viewer can move around + idependently, but if they set any data on the map, all the viewers are + updated. + + <p>The main page isn't interesting, it merely provides a way to open the + viewers: + + <pre><!DOCTYPE HTML> +<html> + <head> + <title>Workers example: Multiviewer</title> + <script> + function openViewer() { + window.open('viewer.html'); + } + </script> + </head> + <body> + <p><button type=button onclick="openViewer()">Open a new + viewer</button></p> + <p>Each viewer opens in a new window. You can have as many viewers + as you like, they all view the same data.</p> + </body> +</html></pre> + + <p>The viewer is more involved: + + <pre><!DOCTYPE HTML> +<html> + <head> + <title>Workers example: Multiviewer viewer</title> + <script> + var worker = createNamedWorker('worker.js', 'core'); + + // CONFIGURATION + function configure(event) { + if (event.message.substr(0, 4) != 'cfg ') return; + var name = event.message.substr(4).split(' ', 1); + // update display to mention our name is name + document.getElementsByTagName('h1')[0].textContent += ' ' + name; + // no longer need this listener + worker.removeEventListener('message', configure, false); + } + worker.addEventListener('message', configure, false); + + // MAP + function paintMap(event) { + if (event.message.substr(0, 4) != 'map ') return; + var data = event.message.substr(4).split(','); + // display tiles data[0] .. data[8] + var canvas = document.getElementById('map'); + var context = canvas.getContext('2d'); + for (var y = 0; y < 3; y += 1) { + for (var x = 0; x < 3; x += 1) { + var tile = data[y * 3 + x]; + if (tile == '0') + context.fillStyle = 'green'; + else + context.fillStyle = 'maroon'; + fillRect(x * 50, y * 50, 50, 50); + } + } + } + worker.addEventListener('message', paintMap, false); + + // PUBLIC CHAT + function updatePublicChat(event) { + if (event.message.substr(0, 4) != 'txt ') return; + var name = event.message.substr(4).split(' ', 1); + var message = event.message.substr(4 + length(name) + 1); + // display "<name> message" in public chat + var dialog = document.getElementById('public'); + var dt = document.createElement('dt'); + dt.textContent = name; + dialog.appendChild(dt); + var dd = document.createElement('dd'); + dd.textContent = message; + dialog.appendChild(dd); + } + worker.addEventListener('message', updatePublicChat, false); + + // PRIVATE CHAT + function startPrivateChat(event) { + if (event.message.substr(0, 4) != 'msg ') return; + var name = event.message.substr(4).split(' ', 1); + var port = event.port; + // display a private chat UI + var ul = document.getElementById('private'); + var li = document.createElement('li'); + var h3 = document.createElement('h3'); + h3.textContent = 'Private chat with ' + name; + li.appendChild(h3); + var dialog = document.createElement('dialog'); + var addMessage = function(name, message) { + var dt = document.createElement('dt'); + dt.textContent = name; + dialog.appendChild(dt); + var dd = document.createElement('dd'); + dd.textContent = message; + dialog.appendChild(dd); + }; + port.onmessage = function (event) { + addMessage(name, event.message); + }; + li.appendChild(dialog); + var form = document.createElement('form'); + var p = document.createElement('p'); + var input = document.createElement('input'); + input.size = 50; + p.appendChild(input); + p.appendChild(document.createTextNode(' ')); + var button = document.createElement('button'); + button.textContent = 'Post'; + p.appendChild(button); + form.onsubmit = function () { + port.postMessage(input.value); + addMessage('me', input.value); + input.value = ''; + return false; + }; + form.appendChild(p); + li.appendChild(form); + } + worker.addEventListener('message', startPrivateChat, false); + + function init() { + // begin receiving messages (messages are queued until you + // either set worker.onmessage or call worker.start()) + worker.start(); + } + </script> + </head> + <body onload="init()"> + <h1>Viewer</h1> + <h2>Map</h2> + <p><canvas id="map" height=150 width=150></canvas></p> + <p> + <button type=button onclick="worker.postMessage('mov left')">Left</button> + <button type=button onclick="worker.postMessage('mov up')">Up</button> + <button type=button onclick="worker.postMessage('mov down')">Down</button> + <button type=button onclick="worker.postMessage('mov right')">Right</button> + <button type=button onclick="worker.postMessage('set 0')">Set 0</button> + <button type=button onclick="worker.postMessage('set 1')">Set 1</button> + </p> + <h2>Public Chat</h2> + <dialog id="public"></dialog> + <form onsubmit="worker.postMessage('txt ' + message.value); message.value = ''; return false;"> + <p> + <input type="text" name="message" size="50"> + <button>Post</button> + </p> + </form> + <h2>Private Chat</h2> + <ul id="private"></ul> + </body> +</html></pre> + + <p>There are several key things worth noting about the way the viewer is + written. + + <p><strong>Multiple listeners</strong>. Instead of a single message + processing function, the code here attaches multiple event listeners, each + one performing a quick check to see if it is relevant for the message. In + this example it doesn't make much difference, but if multiple authors + wanted to collaborate using a single port to communicate with a worker, it + would allow for independent code instead of changes having to all be made + to a single event handling function. + + <p>Because event listeners are registered using <code + title="">addEventListener()</code> instead of <code + title=handler-MessagePort-onmessage>onmessge</code>, the events remain + queued until the <code title=dom-MessagePort-start>start()</code> method + is called on the message port, in the <code title="">init()</code> + function called from the <code title=handler-onload>onload</code> handler. + + <p>Registering event listeners in this way also allows you to unregister + specific listeners when you are done with them, as is done with the <code + title="">configure()</code> method in this example. + + <p>Finally, the worker: + + <pre> +var nextName = 0; +function getNextName() { + // this could use more friendly names + // but for now just return a number + return nextName++; +} + +var map = [ + [0, 0, 0, 0, 0, 0, 0], + [1, 1, 0, 1, 0, 1, 1], + [0, 1, 0, 1, 0, 0, 0], + [0, 1, 0, 1, 0, 1, 1], + [0, 0, 0, 1, 0, 0, 0], + [1, 0, 0, 1, 1, 1, 1], + [1, 1, 0, 1, 1, 0, 1], +]; + +function wrapX(x) { + if (x < 0) return wrapX(x + map[0].length); + if (x >= map[0].length) return wrapX(x - map[0].length); + return x; +} + +function wrapY(y) { + if (y < 0) return wrapY(y + map.length); + if (y >= map[0].length) return wrapY(y - map.length); + return y; +} + +function sendMapData(viewer) { + var data = ''; + for (var y = viewer.y-1; y <= viewer.y+1; y += 1) { + for (var x = viewer.x-1; x <= viewer.x+1; x += 1) { + if (data != '') + data += ','; + data += map[y][x]; + } + } + viewer.port.postMessage('map ' + data); +} + +var viewers = {}; +onconnect = function (event) { + event.port._name = getNextName(); + event.port._data = { port: event.port, x: 0, y: 0, }; + viewers[event.port._name] = event.port._data; + event.port.postMessage('cfg ' + name); + event.port.onmessage = getMessage; + sendMapData(event.port._data); +}; + +function getMessage(event) { + switch (event.message.substr(0, 4)) { + case 'mov ': + var direction = event.message.substr(4); + var dx = 0; + var dy = 0; + switch (direction) { + case 'up': dy = -1; break; + case 'down': dy = 1; break; + case 'left': dx = -1; break; + case 'right': dx = 1; break; + } + event.target._data.x = wrapX(event.target._data.x + dx); + event.target._data.y = wrapY(event.target._data.y + dy); + sendMapData(event.target._data); + break; + case 'set ': + var value = event.message.substr(4); + map[event.target._data.y][event.target._data.x] = value; + for (var viewer in viewers) + sendMapData(viewers[viewer]); + break; + case 'txt ': + var name = event.target._name; + var message = event.message.substr(4); + for (var viewer in viewers) + viewers[viewer].port.postMessage('txt ' + name + ' ' + message); + break; + case 'msg ': + var party1 = event._data; + var party2 = viewers[event.message.substr(4).split(' ', 1)]; + if (party2) { + var channel = new MessageChannel(); + party1.port.postMessage('msg ' + party2.name, channel.port1); + party2.port.postMessage('msg ' + party1.name, channel.port2); + } + break; + } +}</pre> + + <p><strong>Connecting to multiple pages</strong>. Instead of using the + <code title=dom-WorkerGlobalScope-port><a href="#port">port global + variable in the worker, the script uses the <code + title=handler-WorkerGlobalScope-onconnect>onconnect</code> event listener + to listen for multiple connections.</a></code> + + <p><strong>Direct channels</strong>. When the worker receives a "msg" + message from one viewer naming another viewer, it sets up a direct + connection between the two, so that the two viewers can communicate + directly without the worker having to proxy all the messages. + + <p><a href="http://www.whatwg.org/demos/workers/multiviewer/page.html">View + this example online</a>. <h4 id=granting><span class=secno>1.1.5 </span>Granting capabilities</h4> + <p><em>This section is non-normative.</em> + <p class=big-issue>... <h4 id=delegation><span class=secno>1.1.6 </span>Delegation</h4> + <p><em>This section is non-normative.</em> + <p class=big-issue>... <h3 id=conformance><span class=secno>1.2 </span>Conformance requirements</h3>
Received on Wednesday, 6 August 2008 22:11:50 UTC