TogetherJS:Mozilla推出的實(shí)時(shí)協(xié)作工具
我們來(lái)介紹一下TogetherJS,一個(gè)從Mozilla實(shí)驗(yàn)室出來(lái)的實(shí)時(shí)協(xié)作工具。
TogetherJS是這樣的一種服務(wù),你能為一個(gè)已經(jīng)存在的網(wǎng)站增加實(shí)時(shí)協(xié)作特性。使用這種工具,兩個(gè)或者更多的網(wǎng)站或者web應(yīng)用訪問(wèn)者能夠看到別人鼠標(biāo)位置,單擊,追蹤他人的瀏覽記錄,一起編輯表單,觀看視頻,還能夠通過(guò)聲音以及WebRTC聊天。
TogetherJS包括這樣一些特性:
- 查看他人的鼠標(biāo)和點(diǎn)擊情況。
- 查看滾動(dòng)位置。
- 觀察某人瀏覽過(guò)的頁(yè)面。
- 文本聊天。
- 通過(guò)WebRTC語(yǔ)音聊天。
- 表單域同步(文本域,復(fù)選框等等)。
- 同步播放/暫停/追蹤視頻。
- 同一網(wǎng)站跨多個(gè)頁(yè)面延續(xù)會(huì)話。
如何集成
許多TogetherJS的特性無(wú)需更改你的網(wǎng)站。TogetherJS瀏覽DOM,并決定許多應(yīng)該做什么–檢測(cè)表單域,一些諸如CodeMirror和Ace的編輯器,以及在你的頁(yè)面注入工具條。
要想嘗試TogetherJS,僅僅要做的是把這個(gè)添加到你的頁(yè)面里:
- <script src="https://togetherjs.com/togetherjs.js"></script>
然后創(chuàng)建一個(gè)按鈕,讓你的用戶開(kāi)始TogetherJS:
- <button id="collaborate" type="button">Collaborate</button>
- <script>
- document.getElementById("collaborate")
- .addEventListener("click", TogetherJS, false);
如果你想看一些Together做了什么,jsFiddle已經(jīng)啟用了TogetherJS:
只需要單擊下Collaboration,就會(huì)啟動(dòng)TogetherJS了。你也可以自如地使用TogetherJS,下面我們會(huì)講到。
擴(kuò)展你的應(yīng)用
TogetherJS可以通過(guò)瀏覽DOM來(lái)解決一些事情,但不能同步你的JavaScript應(yīng)用。比如,在你的應(yīng)用中有一些條目是通過(guò)JavaScript來(lái)更新的,那么它們就不會(huì)相互間自動(dòng)同步。有時(shí)人們期望能自動(dòng)更新,但即使做了跨頁(yè)面間的DOM同步,我們也不可能會(huì)做到同步底層的JavaScript對(duì)象。不像有些產(chǎn)品,如Firebase或者谷歌Drive實(shí)時(shí)API,TogetherJS沒(méi)有賦予你實(shí)時(shí)的持久性。網(wǎng)站持久性這樣的功能是由你決定,我們僅僅只是在瀏覽器中同步會(huì)話而已。
我們使用了一個(gè)簡(jiǎn)單的繪畫應(yīng)用來(lái)舉例。我們已經(jīng)發(fā)布了完整的例子作為模板,你可以派生以及親自體驗(yàn)。
一個(gè)非常小的繪畫應(yīng)用
我們開(kāi)始一個(gè)非常簡(jiǎn)單的繪畫程序,我們有一個(gè)簡(jiǎn)單的畫布:
- <canvas id="sketch"
- style="height: 400px; width: 400px; border: 1px solid #000">
- </canvas>
然后是一些設(shè)置:
- // get the canvas element and its context
- var canvas = document.querySelector('#sketch');
- var context = canvas.getContext('2d');
- // brush settings
- context.lineWidth = 2;
- context.lineJoin = 'round';
- context.lineCap = 'round';
- context.strokeStyle = '#000';
我們使用畫布的mousedown和mouseup事件去為mousemove事件注冊(cè)move()處理程序。
- var lastMouse = {
- x: 0,
- y: 0
- };
- // attach the mousedown, mousemove, mouseup event listeners.
- canvas.addEventListener('mousedown', function (e) {
- lastMouse = {
- x: e.pageX - this.offsetLeft,
- y: e.pageY - this.offsetTop
- };
- canvas.addEventListener('mousemove', move, false);
- }, false);
- canvas.addEventListener('mouseup', function () {
- canvas.removeEventListener('mousemove', move, false);
- }, false);
然后move()函數(shù)就會(huì)計(jì)算出需要繪畫的線條:
- function move(e) {
- var mouse = {
- x: e.pageX - this.offsetLeft,
- y: e.pageY - this.offsetTop
- };
- draw(lastMouse, mouse);
- lastMouse = mouse;
- }
***是繪畫線條的函數(shù):
- function draw(start, end) {
- context.beginPath();
- context.moveTo(start.x, start.y);
- context.lineTo(end.x, end.y);
- context.closePath();
- context.stroke();
- }
一個(gè)簡(jiǎn)單的繪畫應(yīng)用,這些代碼就足夠了。現(xiàn)在如果你在你的應(yīng)用中啟用了TogetherJS,你會(huì)看到別人頁(yè)面在移動(dòng),并且能看到他們的鼠標(biāo),但你看不到繪畫。讓我們來(lái)解決下!
添加TogetherJS
TogetherJS擁有一個(gè)交換中心,能在同一會(huì)話中相互間回復(fù)消息。這并不翻譯消息,只是來(lái)回往返,包括消息來(lái)自可能在另一頁(yè)面。TogetherJS也能讓應(yīng)用發(fā)送自己的消息,如這樣發(fā)送消息(每個(gè)消息必須有一個(gè)類型):
- TogetherJS.send({
- type: "message-type",
- ...any other attributes you want to send...
- })
然后這樣去監(jiān)聽(tīng):
- TogetherJS.hub.on("message-type", function (msg) {
- if (! msg.sameUrl) {
- // Usually you'll test for this to discard messages that came
- // from a user at a different page
- return;
- }
- });
消息類型是基于命名空間,以致你的應(yīng)用消息不會(huì)意外覆蓋TogetherJS自己的消息。
為了要同步繪畫中我們想觀看的任意一條正在畫的線,并且把這些發(fā)送給其它人:
- function move(e) {
- var mouse = {
- x: e.pageX - this.offsetLeft,
- y: e.pageY - this.offsetTop
- };
- draw(lastMouse, mouse);
- if (TogetherJS.running) {
- TogetherJS.send({type: "draw", start: lastMouse end: mouse});
- }
- lastMouse = mouse;
- }
在發(fā)送前,我們應(yīng)該檢查下TogetherJS確實(shí)正在運(yùn)行(TogetherJS.running)。我們發(fā)送的消息應(yīng)該要一目了然的。
下面,我們要去監(jiān)聽(tīng)這些消息:
- TogetherJS.hub.on("draw", function (msg) {
- if (! msg.sameUrl) {
- return;
- }
- draw(msg.start, msg.end);
- });
當(dāng)我們注冊(cè)這個(gè)監(jiān)聽(tīng)器時(shí),我們不必?fù)?dān)心TogetherJS是否正在運(yùn)行,因?yàn)橹挥性谒谶\(yùn)行時(shí)才能被調(diào)用。
這樣足夠讓我們的繪畫更生動(dòng)并且協(xié)作的。但我們還缺少一個(gè):如果我開(kāi)始畫一個(gè)圖像,然后你加入了我,你僅僅會(huì)看到我畫的新的線條,你看不到我已經(jīng)畫過(guò)的圖像。
為了要解決這個(gè),我們會(huì)去監(jiān)聽(tīng)togertherjs.hello消息,它在每個(gè)客戶端***訪問(wèn)一個(gè)新的頁(yè)面時(shí)發(fā)送。當(dāng)我們監(jiān)聽(tīng)到這個(gè)消息時(shí),我們會(huì)發(fā)送我們的畫布上的圖像給其他人。
- TogetherJS.hub.on("togetherjs.hello", function (msg) {
- if (! msg.sameUrl) {
- return;
- }
- var image = canvas.toDataURL("image/png");
- TogetherJS.send({
- type: "init",
- image: image
- });
- });
現(xiàn)在我們只要去監(jiān)聽(tīng)新的init消息:
- TogetherJS.hub.on("init", function (msg) {
- if (! msg.sameUrl) {
- return;
- }
- var image = new Image();
- image.src = msg.image;
- context.drawImage(image, 0, 0);
- });
僅僅使用這些代碼,TogetherJS讓我們制作了一個(gè)生動(dòng)的繪畫應(yīng)用。當(dāng)然,我們也要去編寫些代碼,但這里是一些TogetherJS為我們處理的事情:
提供用戶一個(gè)URL與另一個(gè)用戶分享去啟動(dòng)會(huì)話。
建立一個(gè)WebSocket連接到中心服務(wù)器,提供客戶端之間的信息往返。
讓用戶設(shè)置名稱和頭像,同時(shí)觀察其他人也在當(dāng)前會(huì)話中。
保持跟蹤,誰(shuí)在線,誰(shuí)離開(kāi),還有誰(shuí)空閑中。
簡(jiǎn)單但必須的特性,像可用的文本聊天
會(huì)話初始化以及跟蹤是由TogetherJS處理。
有些事情我們并沒(méi)在這個(gè)例子中做的:
我們使用了固定大小的畫布,所以我們沒(méi)去處理不同客戶端和不同的分辨率。通常TogetherJS會(huì)處理不同類型的客戶端,并且使用分辨率無(wú)關(guān)的定位(甚至對(duì)響應(yīng)設(shè)計(jì)也有效)。一種修復(fù)的方法可能是保證一個(gè)固定的長(zhǎng)寬比,然后用長(zhǎng)寬的百分比去定位繪畫。
我們沒(méi)使用任何一個(gè)有趣的繪畫工具!可能你不想同步工具—如果我正在使用紅刷筆繪畫,你不能同時(shí)使用綠刷筆來(lái)繪畫,這樣也沒(méi)有理由。
但一些比如清除畫布應(yīng)該要同步。
我們沒(méi)有保存或者加載繪畫。一旦繪畫應(yīng)用有保存和加載,你可能得更多地思考下想同步什么。如果我已經(jīng)創(chuàng)建并且保存了一個(gè)圖片,然后返回到站點(diǎn)加入你的會(huì)話,你的圖像會(huì)覆蓋我的嗎?把每個(gè)圖像放在唯一的URL能更清晰的表明想去編輯哪個(gè)圖像。
想了解更多?
對(duì)TogetherJS架構(gòu)好奇?請(qǐng)查閱技術(shù)簡(jiǎn)介。
在jsFiddle上嘗試TogetherJS。
通過(guò)文檔上的按鈕聯(lián)系我們:”提供實(shí)時(shí)幫助”會(huì)請(qǐng)求啟動(dòng)一個(gè)TogetherJS會(huì)話
在IRC的#togetherjs上聯(lián)系我們。irc.mozilla.org
在Github上查找代碼,如果你遇到bug或者有特性請(qǐng)求,請(qǐng)?zhí)嵋粋€(gè)問(wèn)題。請(qǐng)別害羞,我們對(duì)許多種反饋非常感興趣:想法,潛在用例(以及來(lái)自這些用例的挑戰(zhàn)),和那些看起來(lái)通過(guò)文檔無(wú)法回答的問(wèn)題(這也同時(shí)表示我們文檔上的bug)。請(qǐng)告訴我們有關(guān)潛在的協(xié)同應(yīng)用。
原文鏈接:https://hacks.mozilla.org/2013/10/introducing-togetherjs/