这篇文章主要介绍了适用于 javascript 开发者的 Processing.js 入门教程,感兴趣的小伙伴们可以参考一下
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
- <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 社区来说,一个新而成熟并且接近全功能的图象编程语言从而诞生了。
学会 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 和
- <!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,去查找
预编译 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 代码移到一个
3)、从 javascript 里访问 processing
得出个结论是从 Processing 代码里访问 javascript 比反过来要容易的多,因为被 Processing 解析器创建 javascript 没有直接暴露在全局对象里,因此你只能通过 Processing.instances 的属性来访问。
Processing 的构造器一直都在监视实例的创建,并且使得他们可以使用 getInstanceById() 方法。默认,当
当你有一个能够访问 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 的。
来源: http://www.phperz.com/article/17/0217/266988.html