這個入門指導是為javascript開發者寫的。讀這個文檔之前,你最好掌握javascript和web開發編程,並還會非常基本的 Processing 知識。
目錄:
為沒有耐心看長篇大論的人准備:
如果你很著急入門,那麼你就需要知道以下幾點:
1、Processing.js 把 Processing 代碼轉變成能夠在浏覽器端運行的javascript代碼,實質是通過<canvas>標簽來實現繪圖的;
2、為了使用它,你的首先下載 Processing.js;
3、創建你的 後綴名為".pde"的 Processing 文件,它和通常你創建的普通文本文件一樣,例如: hello-web.pde
4、創建一個 html 頁面,然後在頁面裡外引用 Processing.js文件,再添加一個<canvas>標簽,該<canvas>標簽上指明有你的 sketch file(顧名思義,草圖文件,就是Processing 文件),sketch file 可以有多個文件,多個文件用空格隔開。例如:
<script src="processing-1.3.6.min.js"></script> <canvas data-processing-sources="hello-web.pde"></canvas>
加載你的 web 頁面,processing.js 將解析、翻譯 sketch file,然後你的sketch file就會運行在浏覽器裡。
Processing.js的來源?
Processing為何物?
Processing 語言原先被MIT創建,被作為多媒體實驗室 和美學&計算機組的一部分。借助Processing能打通軟件開發者,藝術家,數據可視化工程師們之間的隔閡,並且能夠讓編程人員和非編程人員非常容易地勝任視覺化工作。Processing 是用java創建的,你可以把它認為是一種被簡化了的java,並且帶被簡化了的用來繪畫和繪圖的API。
Processing 能在web端做點什麼?
Processing 擁有大型並且和活躍的社區群體,他們擅長創建2D和3D圖象,可視化數據套件,音頻,視頻等等。因為HTML5,web端擁有了 canvas,audio,video,這些原先只能通過flash 和java插件擁有的功能。與此同時,高級的javascript引擎使得javascript 可以完全勝任以前做起來很慢的事情。
通過把Processing語言移植到web端,Processing 和 web社區都會收益。對於Processing來說,這意味這源碼不僅可以在桌面上工作,而且可以在跑在浏覽器上。對於web社區來說,一個新而成熟並且接近全功能的圖象編程語言從而誕生了。 <canvas>元素對於直接用javascript提供的接口來開發的編程人員來說,這些原生接口太低級了,所以更高級的庫就是必要的。Processing.js就能夠被當作是這樣的簡化操作2D和3Dcanvas的庫。
學會processing,需要多少工作要做
Processing語言小而完整,所以非常容易學。本文檔不僅僅嘗試去教你Processing,還會鼓勵你去尋找 Processing的規范教程,書和例子。任何Processing代碼或者概念都應該映射到Processing.js裡(下邊列出的除外)。你可以跳過Processing贊成的java語法的javascript,使用純javascript來與Processing的畫圖API一起使用。
使用Processing的方式
Processing.js創建的初衷是能夠讓Processing開發者和Processing代碼(通常是指 sketches)不用修改就可以在web端運行。因此,被推薦的方式就是用Processing.js來寫processing 代碼,然後通過Processing.js轉換成javascript後運行它。
隨著時間的推移,一些web開發者也開始使用processing.js,他們就要求設計的API從Processing 語脫離出來使用。因此,我們提供一種可以用純javascript語言來開發的方式,並且可以使用Processing的方法和對象。注意:Processing.js是放在首位的,並且是Processing向web開放的最重要的一部分,具有有利於兼容Processing的設計決定權。它不是被設計成一個通用的HTML 畫圖庫。已經說過,它是可以當作canvas高級畫圖API來用。
接下來我們討論下在web頁面裡使用的各種Processing.js方法。
寫純 Processing 代碼
這種寫法是使用Processing.js的首選方法,並且已經在 Processing.js for Processing Devs quick start guide 做了長篇的介紹。概括總結如下:
1、下載 processing.js
2、創建一個單獨的 Processing 文件,或多個文件,名字可以隨便叫,只要後綴名是".pde"就行。
3、創建一個web頁面,頁面包括 Processing.js 和 <canvas>標簽,<canvas> 的信息含有 sketch file(s)的路徑和用空格隔開的Procesing 文件名列表,並且這些列表名是放在canvas的屬性data-processing-sources上。例如:
<!DOCTYPE html> <html> <head> <title>Hello Web - Processing.js Test</title> <script src="processing-1.3.6.min.js"></script> </head> <body> <h1>Processing.js Test</h1> <p>This is my first Processing.js web-based sketch:</p> <canvas data-processing-sources="hello-web.pde"></canvas> </body> </html>
當頁面加載完(on page load),processing.js將會自動浏覽web頁面的document,去查找<canvas>的屬性data-processing-sources,然後用XMLHTTPRequest去下載 這些文件,將它們塞進從porcessing到javascript的翻譯器,翻譯後的javascript將會通過eval 函數來執行。
預編譯 processing 代碼 為 javascript
Processing.js 自動下載並將所有Processing 代碼轉成 javascript。它做這些是使用Processing.compile()方法來完成的,並且 那些相關的processing構建工具 或者實用工具也可以做同樣的事情。
為了獲得 從Processing 代碼編譯後的代碼(例如,JavaScript適用於processing.js運行),請按如下操作:
// hard-coded Processing code, text from an HTML widget, downloaded text, etc. var processingCode = "..."; var jsCode = Processing.compile(processingCode).sourceCode;
例如,轉化如下的Processing 代碼 會生成 在它之下的 編譯的來的javascript代碼:
// Processing code void setup() { size(200, 200); background(100); stroke(255); ellipse(50, 50, 25, 25); println("hello web!"); } // "Comiled" JavaScript code // this code was autogenerated from PJS (function(processing, $constants) { function setup() { processing.size(200, 200); processing.background(100); processing.stroke(255); processing.ellipse(50, 50, 25, 25); processing.println("hello web!"); } processing.setup = setup; })
只寫 javascritp的 processing.js code
前面的方法把 processing 代嗎生成了 javascript 代碼,但是你也可以單獨寫javascript。processing.js的解析器將Processing代碼轉化成javascript方法,然後運行它。因此,完全有可能跳過Processing代碼,只寫javascript 方法,將方法傳給一個Processing實例。這有個例子如下:
function sketchProc(processing) { // Override draw function, by default it will be called 60 times per second processing.draw = function() { // determine center and max clock arm length var centerX = processing.width / 2, centerY = processing.height / 2; var maxArmLength = Math.min(centerX, centerY); function drawArm(position, lengthScale, weight) { processing.strokeWeight(weight); processing.line(centerX, centerY, centerX + Math.sin(position * 2 * Math.PI) * lengthScale * maxArmLength, centerY - Math.cos(position * 2 * Math.PI) * lengthScale * maxArmLength); } // erase background processing.background(224); var now = new Date(); // Moving hours arm by small increments var hoursPosition = (now.getHours() % 12 + now.getMinutes() / 60) / 12; drawArm(hoursPosition, 0.5, 5); // Moving minutes arm by small increments var minutesPosition = (now.getMinutes() + now.getSeconds() / 60) / 60; drawArm(minutesPosition, 0.80, 3); // Moving hour arm by second increments var secondsPosition = now.getSeconds() / 60; drawArm(secondsPosition, 0.90, 1); }; } var canvas = document.getElementById("canvas1"); // attaching the sketchProc function to the canvas var processingInstance = new Processing(canvas, sketchProc);
這兒是創建了一個 sketch 方法,這個方法就和解析器生成的代碼一樣。這個方法需要一個參數,它是一個指向某個由Processing構造器生成的processing對象(例如,Processing運行時對象)的引用,任何 Procesing方法或者對象都一個作為它的屬性來訪問。
一旦這個方法完成,並且通過,隨著就有一個引用指向canvas,一個引用指向 Processing構造器(記得用"new")。
寫一個 Processing 和 javascript結合的文件
人們經常問的第一個問題就是processing.js是否可以讀取來自正在運行Processing sketch的文件的值。或者反過來的觀點。答案是肯定的。
Processing.js 轉化 Processing 代碼 成一個含有函數閉包javascript代碼。所有你創建的變量和方法沒有被綁定到全局變量上(即:window)。然而,你仍然可以訪問他們。
1)、從Processing裡訪問 javascript對象
從Processing代碼轉化成javascript並且和其他函數一樣運行起來,所有Processing代碼都可以訪問全局對象。這意味著你可以在全局腳本模塊裡創建一個變量或者方法,它們就可以自動被Processing來訪問。考慮這樣一個例子:
首先是 Processing 文件,mixed.pde:
String processingString = "Hello from Processing!"; void setup() { printMessage(jsString + " " + processingString); }
接下來是web頁面:
<!DOCTYPE html> <html> <head> <title>Hello Web - Accessing JavaScript from Processing</title> <script src="processing-1.3.6.min.js"></script> </head> <body> <div id="msg"> </div> <canvas data-processing-sources="mixing.pde"></canvas> <script type="application/javascript"> var jsString = "Hello from JavaScript!"; var printMessage = function (msg) { document.getElementById('msg').innerHTML = "Message: " + msg; }; </script> </body> </html>
這裡 Processing.js允許使用的變量和方法聲明在 Processing代碼的外邊。
2)、javascript 和 Processing代碼的混合
前面的例子使得javascript和processing代碼各自放在單獨的文件裡,當它們之間的界限不是分的很近時。
因為Processing.js在轉化代碼時,也可能直接將他們直接混在一起。Processing.js解析器保留包含在Processing代碼裡的 javascript不變,這樣就允許開發者能寫processing和javascript的混合代碼(注意:這也就是為什麼 processing.js裡沒有使用純processing解析器的原因)。這是一個之前也是用這個方法寫的例子:
var jsString = "Hello from JavaScript!"; var printMessage = function(msg) { document.getElementById('msg').innerHTML = "Message: " + msg; }; String processingString = "Hello from Processing!"; void setup() { printMessage(jsString + " " + processingString); }
有些javascript語法很難用這種方式混在一起寫(例如:正則語法)。如果是那樣的情況的話,你可以簡單地將純javasript代碼移到一個<script>代碼塊裡,然後像上邊“Accessing JavaScript Objects from Processing”描述的那樣來訪問它。
3)、從javascript裡訪問 processing
得出個結論是從Processing 代碼裡訪問javascript比反過來要容易的多,因為被Processing解析器創建javascript沒有直接暴露在全局對象裡,因此你只能通過Processing.instances 的屬性來訪問。
Processing 的構造器一直都在監視實例的創建,並且使得他們可以使用getInstanceById()方法。默認,當<canvas>有屬性 data-processing-source時,它的id將會作為Processing 實例的唯一識別負。如果沒有id屬性,你可以用Proessing.instance[0]來訪問。
當你有一個能夠訪問Processing實例的引用時,你就可以調用它像這樣:
<!DOCTYPE html> <html> <head> <title>Hello Web - Controlling Processing from JavaScript</title> <script src="processing-1.3.6.min.js"></script> </head> <body> <canvas id="sketch" data-processing-sources="controlling.pde"></canvas> <button onclick="startSketch();"> Start</button> <button onclick="stopSketch();"> Stop</button> <script type="application/javascript"> var processingInstance; function startSketch() { switchSketchState(true); } function stopSketch() { switchSketchState(false); } function switchSketchState(on) { if (!processingInstance) { processingInstance = Processing.getInstanceById('sketch'); } if (on) { processingInstance.loop(); // call Processing loop() function } else { processingInstance.noLoop(); // stop animation, call noLoop() } } </script> </body> </html>
在DOM結構中有2個按鈕,他們被用來讓用戶選擇開始或暫停正在運行的Processing sketch.
他們直接在javascript中控制Processing實例(在頁面裡你可能有多個,或者藏在div中),通過調用Processing的方法:loop()和noLoop()。這些Processing 的方法可以在其他的文件中找到。
作為一個使用Processing.js的開發者必須知道的事情:
當 Processing.js試圖去完全兼容 Processing時,就有些不同的事情或者需要解決辦法。我們也增加了一些web規范的功能來使Processing更容易被使用。 這裡有一些技巧和提示在你開始使用Processing.js做復雜的sketch時可能有幫助。
Processing.js提供通過“externals”屬性來訪問各種 DOM/javascript對象
每個Processing 實例(即:Processing.instances)包含有一個"external"屬性,它是一個對象,包含各種指向非常有用的非Processing 的DOM/javascritp 對象,例如:
canvas--sketch被綁定上的畫板 context--畫板的執行上下文 onblur and onfocus--事件處理器
如果一個除法表達式期望產生一個整型值,那麼這可能需要顯式轉換
當將Processing代碼轉化成javascript,涉及整型 vs 浮點型的除法的時候,有一個有bug的class會出現這個問題。
在Processing代碼中出現某個東西直接除以整數的代碼塊,當被轉化成Processing時,可能有時出現問題,因為,整型編程雙精度型,被引入了一個小數部分。修補這個bug的方法是 顯式轉換任何除法,正如展示的做法:
// before int g = mouseX / i; // after int g = (int)(mouseX / i);
Processing.js有個欺騙在模擬 Processing的異步輸入輸出
Processing 使用一個同步輸入輸出的模型,這就意味著 像loadImage()方法這樣,需要相對長時間去執行,然而當他們執行期間,又沒有任何事發生,程序等到它loadImage()執行完才去執行下一行語句。這就意味這可以依靠像loadImage()這樣的方法返回的值用在接下來的代碼中。
但是web浏覽器卻不是這樣的,它使用的是異步輸入輸出模型,這意味著加載外部資源的方法不能使得程序等到他們加載完再執行。為了實現Processing的load方法,你不得不使用一個特殊的Processing的指令。
Processing.js指令提示浏覽器,指令是寫在注釋裡而不是Processing自身代碼。這是一個典型的 Processing sketch,它需要同步加載一個圖片然後畫出它:
PImage img; void setup() { img = loadImage("picture.jpg"); image(img, 0, 0); }
這些代碼在含有Processing.js的浏覽器裡將不會執行,因為圖片文件 picture.jpg被加載完之前就被調用了。修補這個bug的辦法是讓在sketch 開始執行前就把圖片加載好,並且緩存起來,就是所說的預加載技術。這是修改後的代碼:
/* @pjs preload="picture.jpg"; */ PImage img; void setup() { img = loadImage("picture.jpg"); image(img, 0, 0); }
注意:放在代碼頂部的額外的注釋行。"@jps"指令是給Processjing.js用的,不是給開發者用的。可以把它認為成額外的代碼行,它們將在程序執行前就被執行了。
如果你有多個圖片被加載,可以使用如下列表:
/* @pjs preload="picture.jpg,picture2.jpg,picture3.png"; */
Processing.js需要更多的注意在變量的命名上比Processing
javascript其中一個最強大的特性就是它的動態,弱類型的性質。因為java是強類型的語言,所以Processing也是,他們能重復命名而不用還怕產生歧義(例如:方法的重載),Processing.js就不行。不能進入javascript的內部工作,所以對Processing.js的開發者來說,最好的建議就是不要用 function/class/etc/,也不要用來自Processing的名字來命名變量。例如,一個叫 line的變量可能看起來合理,但是它會導致問題,因為它和Processing與Procesing.js內置的函數名line()一樣。
當要覆蓋重載的父類方法時,Processing需要你的幫助
如果你的代碼使用子類覆蓋一個或多個父類裡重載的方法,你需要“假”覆蓋,因為,每個方法簽名,你通常就沒改動過:
class X { void doSomething() { ... } void doSomething(float x, float y) { ... } } class Y extends X { void doSomething() { // different code from compared to the super class } // even though we don't override this method, // its signature must be added to prevent Pjs // from getting the method chain wrong: void doSomething(float x, float y) { super.doSomething(x,y); } }
盡管在Processing裡 你不需要實現擁有(float,float)簽名的空方法doSomething,但是這樣做幾乎是必須的,這是為了確保Processing.js在調用方法時不被搞暈。
直接將Processing 代碼放在web頁面裡也是可以的
在canvas上,用一個 data-processing-source屬性包含Processing.js加載的外部文件的做法是首選,但是推薦的方式在web頁面裡外引用腳本。但是寫成行內引用也是可以的。
把上邊例子的代碼作為行內引用的方式,有必要的改動一點:
<script src="processing-1.3.6.min.js"></script> <script type="application/processing" data-processing-target="pjs"> void setup() { size(200, 200); background(100); stroke(255); ellipse(50, 50, 25, 25); println('hello web!'); } </script> <canvas id="pjs"> </canvas>
這些代碼是更復雜了,因為它沒有指出那個canvas配那個腳本文件(即:你可以在一個頁面引用多個Processing sketch,同樣也可以有多個canvas)。也沒有說明腳本的"type"屬性,這個屬性是用來區別javascript和Processing代碼的(浏覽器將忽略 Processing 腳本)。最後,注意:"id"和"target"屬性的用法,它倆是用來連接Processing腳本和相關的canvas的。
以上就是本文的全部內容,希望大家對Processing.js有所認識。