2014-04-15 72 views
0

我已經看到了很多關於網絡工作者和<canvas>數據傳遞的線程,我不確定我的場景是否可以實現。Web工作者和畫布數據

我想創建一個小網站,供用戶學習使用Javascript進行編碼。當用戶點擊一個按鈕時,代碼將在網絡工作者中運行。爲了幫助他們,我也創建了「印刷」(這基本上只是將文本添加到一個<pre>元素的方法。

// get code from user and prepend helper "functions" 
var userCode = editor.getValue(); 
var codeWithMessages = "\n\ 
    function print(data) { postMessage(\"\"+data); } \n\ 
    function println(data) { postMessage(\"\"+data+\'\\n\'); } \n\ 
    function alert(data) { postMessage('ALERT'+data); } \n\ 
    \n" + userCode; 
var codeWithMessagesAndExit = codeWithMessages + "\npostMessage('exit()');"; 
var blob = new Blob([codeWithMessagesAndExit], {type: 'application/javascript'}); 
// Obtain a blob URL reference to our worker 'file'. 
var blobURL = window.URL.createObjectURL(blob); 
outer.worker = new Worker(blobURL); 

... 
// handle messages by "printing" to the run-output element, or display 
// a success message when finishing 
outer.worker.addEventListener('message', function (event) { 

     if (event.data == "exit()") { 
      outer.worker.terminate(); 
      outer.worker = null; 

      outer.codeRunStatus = outer.CODE_RUN_SUCCESS; 
      outer.errorMessage = null; 
      outer.outputFromLatestRun = $("#run-output").text(); 
      $("#run-output").append("<span class='code-run-success'>\nKörning klar</span>"); 
      enableButtons(); 
     } 
     else if (event.data.indexOf("ALERT") == 0) { 
      alert(event.data.substring(5)); 
     } 
     else { 
      $("#run-output").append(event.data); 
     } 
    }, false); 
// start the worker 
outer.worker.postMessage(); 

現在我想在畫布添加到頁面,因此用戶可以編寫代碼來繪製上它。

var canvas = document.getElementById("user-canvas"); 
var ctx = canvas.getContext("2d"); 
var imgData = ctx.getImageData(0,0,canvas.width,canvas.height); 
// rest same as above 
outer.worker.postMessage(imgData); 

我不知道如何從這裏着手。理想情況下,用戶可以編寫類似

myCanvas.fillStyle = "rgb(200,0,0)"; 
myCanvas.fillRect (10, 10, 55, 50); 

,然後有事件監聽器此處理像我有m個做y print()功能。這可能嗎?

回答

3

無法從WebWorker訪問DOM。

我能看到的最好方法是在webworker中重新定義這個對象,並定義一個協議將每個調用傳遞給一個方法。但是當你需要像圖像這樣的其他物體時它不起作用。

工人方:

var CanvasRenderingContext2D = function() { 
    this.fillStyle = "black"; 
    this.strokeStyle = "black"; 
    ... 
    this.lineWidth = 1.0; 
}; 

["fillRect", "strokeRect", "beginPath", ... "rotate", "stroke"].forEach(function(methodName) { 
    CanvasRenderingContext2D.prototype[methodName] = function() { 
     postMessage({called: methodName, args: arguments, currentObjectAttributes: this}); 
    }; 
}); 

... 

var myCanvas = new CanvasRenderingContext2D(); 
myCanvas.fillStyle = "rgb(200,0,0)"; 
myCanvas.fillRect(10, 10, 55, 50); 

主頁面側:

var canvas = document.createElement("canvas"); 
var context = canvas.getContext("2d"); 
var worker = new Worker(...); 
worker.onMessage = function(event) { 
    var data = event.data; 

    // Refreshing context attributes 
    var attributes = data.currentObjectAttributes; 
    for(var k in attributes) { 
     context[k] = attributes[k]; 
    } 

    // Calling method 
    var method = context[data.called]; 
    method.apply(context, data.args); 
}; 

編輯:

我試圖把它與你的代碼集成(未測試)。爲了整合它,我必須改變工作人員發送的消息的結構。

// get code from user and prepend helper "functions" 
var userCode = editor.getValue(); 
var codeWithMessages = '\n\ 
function print (data) { postMessage(["print", data.toString()]); } \n\ 
function println(data) { postMessage(["print", data.toString() + "\\n"]); } \n\ 
function alert (data) { postMessage(["alert", data.toString()]); } \n\ 
var CanvasRenderingContext2D = function() { \n\ 
    this.fillStyle = "black"; \n\ 
    this.strokeStyle = "black"; \n\ 
    /* ... */ \n\ 
    this.lineWidth = 1.0; \n\ 
}; \n\ 
["fillRect", "strokeRect", "beginPath", /* ... */ "rotate", "stroke"].forEach(function(methodName) { \n\ 
    CanvasRenderingContext2D.prototype[methodName] = function() { \n\ 
     postMessage(["canvas", {called: methodName, args: Array.prototype.slice.call(arguments), currentObjectAttributes: this}]); \n\ 
    }; \n\ 
});\n' + userCode; 
var codeWithMessagesAndExit = codeWithMessages + "\npostMessage(['exit']);"; 
var blob = new Blob([codeWithMessagesAndExit], {type: 'application/javascript'}); 
// Obtain a blob URL reference to our worker 'file'. 
var blobURL = window.URL.createObjectURL(blob); 
outer.worker = new Worker(blobURL); 

... 

// Define your canvas ... 
var canvas = document.createElement("canvas"); 
var context = canvas.getContext("2d"); 

// handle messages by "printing" to the run-output element, or display 
// a success message when finishing 
outer.worker.addEventListener('message', function (event) { 
    var method = event.data[0] || null; 
    var data = event.data[1] || null; 

    if(method == "canvas") { 
     // Refreshing context attributes 
     var attributes = data.currentObjectAttributes; 
     for(var k in attributes) { 
      context[k] = attributes[k]; 
     } 

     // Calling method 
     var method = context[data.called]; 
     method.apply(context, data.args); 
    } else if(method == "exit") { 
     outer.worker.terminate(); 
     outer.worker = null; 

     outer.codeRunStatus = outer.CODE_RUN_SUCCESS; 
     outer.errorMessage = null; 
     outer.outputFromLatestRun = $("#run-output").text(); 
     $("#run-output").append("<span class='code-run-success'>\nKörning klar</span>"); 
     enableButtons(); 
    } else if(method == "alert") { 
     alert(data); 
    } else if(method == "print") { 
     $("#run-output").append(data); 
    } else { 
     $("#run-output").append(event.data); 
    } 
}, false); 
// start the worker 
outer.worker.postMessage(); 
+0

這看起來像我之後。我可以將這些與我目前的「打印」功能結合起來嗎?我得到'Uncaught TypeError:無法讀取未定義的'apply'屬性 –

+0

@ pg-robban您可以將它與'print'結合使用,但它需要更改消息的結構。使用最新的瀏覽器,您可以直接發送結構化對象和數組。關於你的錯誤,你是否在你的例子中用'ctx'重命名了'context'?我將編輯我的答案,將其與您的代碼整合。 –

+0

這是我現在的代碼,以防您需要它:http://pastebin.com/fh6F0wvY –