HTML5基础,第4部分:点睛之笔Canvas
图1给出了一个100像素X100像素的画布区:
1. 左上角是x=0,y=0。
2. x的值水平增加,y的值垂直增加。
3. 右下角是x=100,y=100。
4. 中间的点是x=50,y=50。
开始第一步
要在画布上放置任何东西的话,你首先必须在HTML文件中定义画布。你必须创建访问< canvas>标签的JavaScript代码,并通过与HTML5 Canvas API通信来绘制你的图像。
< canvas>标签的基本结构如下:
< canvas id="myCanvas" width="200" height="200">< /canvas>
canvas元素自身有两个属性:width和height,除此之外,canvas还拥有所有主要的HTML5属性,比如说class、id和name等。id属性被用在上面所示的代码中,JavaScript使用这里创建的canvas的id来表示要在上面绘画的画布。JavaScript使用document.getElementById()方法来确定正确的画布,如下面代码所示:
var canvas = document.getElementById("myCanvas");
每个画布都必须要有一个context(上下文)的定义,如下面代码所示。就目前的情况来说,官方规范只承认一个2D环境:
var context = canvas.getContext("2d");
在标识画布并指明了它的上下文之后,你就做好了开始绘画的准备了。
绘图工具、效果和转换
在HTML5 Canvas的这一讨论过程中,我们对各种绘图工具、效果和转换都查看一番。绘图工具包括:
1. 线条你会用到的Canvas效果包括:
1. 填充和描边要讨论的转换包括:
1. 缩放绘制线段
要在画布上绘制线段的话,你可以使用moveTo()、lineTo()和stroke()方法,此外,你要使用beginPath()方法来重置当前路径:
1. context.beginPath();
2. Context.moveTo(x,y);
3. Context.lineTo(x,y);
4. Context.stroke(x,y);
beginPath()方法开始一条新的路径,在使用不同的子路径绘制一条新的线段之前,你必须要使用beginPath()来标明一个绘制过程要遵循的新起点。在绘制第一条线段时,beginPath()方法的调用不是必须的。
moveTo()方法指明新的子路径从哪里开始,lineTo()方法创建子路径。你可以使用lineWidth和strokeStyle来改变线段的外观,lineWidth元素改变线段的粗细,strokeStyle改变颜色。
在图2中,三条线段分别用蓝色、绿色和紫色画了出来。
图2. 画有三条不同颜色的线段的画布
图2中的线段由清单1中的代码来创建,蓝色的线段有着圆弧形的端点,该线段是由首个context.beginPath()这一开始新路径的建立的方法来创建的,其后紧跟着:
1. context.moveTo(50, 50),该方法把线路的起点置于(x=50, y=50)
2. context.lineTo(300,50),该方法标识线段的终点
3. context.lineWidth = 10,该属性是线段的宽度
4. context.strokeStyle = "#0000FF",该属性是线段的颜色
5. context.lineCap = "round",该属性把端点设成是圆弧状的
6. context.stroke(),该方法真正在画布上绘制该线段
所有线段的长度都是50像素,尽管它们看上去不一样长——这是由线段的线帽(line cap)造成的视觉错觉。可用的线帽有三种:
1. Context.round (blue)
2. Context.square (green)
3. Context.butt (purple)——默认值
对接(butt)线帽是默认值,当你使用圆形(round)或是方形(square)的线帽风格时,线段的长度会增加,加上一段相当于线段宽度的长度。例如,一个长度为200像素,宽度为10像素,有着圆形或是方形线帽风格的线段,其最终的线段长度是210像素,因为每个线帽都都往线段的每一端加上了5个像素的长度。而一个长度为200像素,宽度为20像素,有着圆形或是方形的线帽风格的线段的最终长度是220像素,因为每个线帽都往线段每一端加上了10像素的长度。
通过执行和修改清单1中的代码来更好地理解线段的绘制方式。
清单1. 在画布上创建三条不同颜色的线段
< !DOCTYPE HTML>
< html>
< head>
< title>Line Example< /title>
< style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
< /style>
< script>
window.onload = function() {
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
// 有着圆形端点的蓝色线段
context.beginPath();
context.moveTo(50, 50);
context.lineTo(300,50);
context.lineWidth = 10;
context.strokeStyle = "#0000FF";
context.lineCap = "round";
context.stroke();
// 有着方形端点的绿色线段
context.beginPath();
context.moveTo(50, 100);
context.lineTo(300,100);
context.lineWidth = 20;
context.strokeStyle = "#00FF00";
context.lineCap = "square";
context.stroke();
// 有着对接端点的紫色线段
context.beginPath();
context.moveTo(50, 150);
context.lineTo(300, 150);
context.lineWidth = 30;
context.strokeStyle = "#FF00FF";
context.lineCap = "butt";
context.stroke();
};
< /script>
< /head>
< body>
< canvas id="myCanvas" width="400" height="200">
< /canvas>
< /body>
< /html>
绘制矩形
有三个方法可用来在画布上给出一个矩形的区域:
1. fillRect(x,y,width,height),该方法绘制一个有填充的矩形
2. strokeRect(x,y,width,height),该方法绘制一个矩形的外边框
3. clearRect(x,y,width,height),该方法清空指定的区域,使之变得完全透明
对于这三个方法中的每个来说,x和y表示的都是画布上相对于矩形(x=0, y=0)的左上角的位置,width和height分别是矩形的宽度和高度。
图3显示了由清单2中的代码创建的三个矩形。
图3. 画有矩形的画布
fillRect()方法创建了一个以缺省的黑色为填充色的矩形;clearRect()方法在第一个矩形的中心部分清除出一个矩形区域,该区域位于由fillRect()方法产生的矩形的中央位置;strokeRect创建了一个只有可见的黑色边框的矩形。
清单2. 矩形画布的代码
< !DOCTYPE HTML>
< html>
< head>
< title>Rectangle Example< /title>
< style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #000000;
background-color: #ffff00;
}
< /style>
< script type="text/javascript">
function drawShape(){
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.fillRect(25,25,50,50);
context.clearRect(35,35,30,30);
context.strokeRect(100,100,50,50);
}
< /script>
< /head>
< body onload="drawShape();">
< canvas id="myCanvas" width="200" height="200">< /canvas>
< /body>
< /html>
绘制圆弧、曲线、圆和半圆
圆和半圆都是使用arc()方法来绘制,arc()方法用到了六个参数:
context.arc(centerX, centerY, radius, startingAngle, endingAngle, antiClockwise);
centerX和centerY参数是圆的中心坐标,radius就是数学上的半径:从圆心到圆周线的一条直线。弧形是作为所定义的圆的一部分来创建的,startAngle和endAngle参数分别是圆弧的起点和终点,以弧度为单位。anticlockwise参数是一个布尔(Boolean)值,当其值为true时,弧形按逆时针方向来绘制,当其值为false时,弧形按顺时针方向来绘制。
要使用arc()方法来绘制圆的话,把起始角度定义成0,把结束角度定义成2*PI,如下所示:
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
要使用arc()方法来绘制半圆的话,把结束角度定义成startingAngle + PI,如下所示:
context.arc(centerX, centerY, radius, startingAngle, startingAngle + Math.PI, false);二次曲线
quadraticCurveTo()方法被用来创建一条二次曲线,如下所示。二次曲线通过上下文中的点、一个控制点以及一个结束点来定义。控制点确定了线的曲度。
context.moveTo(x, y);
context.quadraticCurveTo(controlX, controlY, endX, endY);
贝塞尔曲线
正和二次曲线一样,贝塞尔曲线也有一个起点和一个终点,但和二次曲线不同的是,它有两个控制点:
context.moveTo(x, y);
context.bezierCurveTo(controlX1, controlY1, controlX2, controlY2, endX, endY);
你可使用bezierCurveTo()方法来创建贝塞尔曲线,因为贝塞尔曲线是由两个控制点而不仅是由一个控制点来定义的,所有你可以创造出更加复杂的曲度来。
图4的显示——从左到右——为一条圆弧、一条二次曲线、一条贝塞尔曲线、一个半圆和一个圆。
图4. 圆弧、曲线和圆
图4的内容是用清单3中的代码来创建的。
清单3. 圆弧、曲线和圆的代码
< !DOCTYPE HTML>
< html>
< head>
< title>Arcs, Curves, Circles, & Semicircles< /title>
< style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
< /style>
< script>
function drawArc(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var centerX = 100;
var centerY = 160;
var radius = 75;
var startingAngle = 1.1 * Math.PI;
var endingAngle = 1.9 * Math.PI;
var counterclockwise = false;
context.arc(centerX, centerY, radius, startingAngle,
endingAngle, counterclockwise);
context.lineWidth = 10;
context.strokeStyle = "black";
context.stroke();
};
function drawQuadratic(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
context.moveTo(200, 150);
var controlX = 288;
var controlY = 0;
var endX = 388;
var endY = 150;
context.quadraticCurveTo(controlX, controlY, endX, endY);
context.lineWidth = 10;
context.strokeStyle = "black";
context.stroke();
};
function drawBezier(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
context.moveTo(350, 350);
var controlX1 = 440;
var controlY1 = 10;
var controlX2 = 550;
var controlY2 = 10;
var endX = 500;
var endY = 150;
context.bezierCurveTo(controlX1, controlY1, controlX2,
controlY2, endX, endY);
context.lineWidth = 10;
context.strokeStyle = "black";
context.stroke();
};
function drawCircle(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var centerX = 450;
var centerY = 375;
var radius = 70;
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = "#800000";
context.fill();
context.lineWidth = 5;
context.strokeStyle = "black";
context.stroke();
};
function drawSemicircle(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var centerX = 100;
var centerY = 375;
var radius = 70;
var lineWidth = 5;
context.beginPath();
context.arc(centerX, centerY, radius, 0, Math.PI, false);
context.closePath();
context.lineWidth = lineWidth;
context.fillStyle = "#900000";
context.fill();
context.strokeStyle = "black";
context.stroke();
};
window.onload = function (){
drawArc();
drawQuadratic();
drawBezier();
drawCircle();
drawSemicircle()
}
< /script>
< /head>
< body>
< canvas id="myCanvas" width="600" height="500">
< /canvas>
< /body>
< /html>
转换:平移、缩放和旋转
translate()、scale()和rotate()方法都会修改当前的矩阵。translate(x, y)方法把画布上的项目移动到网格上的不同点上,在translate(x, y)方法中,(x,y)坐标指明了图像在x方向和y方向上应该移动的像素数。
如果你使用drawImage()方法来在(15,25)这一位置绘制一个图像的话,你可以使用(20,30)作为参数的来调用translate(),该调用把图像放在(15+20, 25+30) = (35, 55)这一位置上。
scale(x,y)方法改变图像的大小,x参数指明水平方向的比例系数,y参数指明垂直方向的比例系数。例如,scale(1.5, .75)将创建一个在x方向加大50%,而在y方向只相当于当前尺寸75%的图像。rotate(angle)方法返回一个基于指定角度的对象。
图5是一个可以使用translate()、scale()和rotate()进行渲染的图像例子。
图5. 使用转换
清单4提供的代码创建了图5中的图像。
清单4. 创建转换的代码
< !DOCTYPE HTML>
< html>
< head>
< Title>Transformations Example< /title>
< script>
window.onload = function() {
var canvas=document.getElementById("myCanvas");
var context=canvas.getContext("2d");
var rectWidth = 250;
var rectHeight = 75;
// 把context平移到画布的中心
context.translate(canvas.width/2,canvas.height/2);
// y方向的组成减半
context.scale(1,0.5);
// 顺时针旋转45度
context.rotate(-Math.PI/4);
context.fillStyle="blue";
context.fillRect(-rectWidth/2,-rectHeight/2,
rectWidth,rectHeight);
// 水平方向翻转context
context.scale(-1,1);
context.font="30pt Calibri";
context.textAlign="center";
context.fillStyle="#ffffff";
context.fillText("Mirror Image",3,10);
}
< /script>
< /head>
< body>
< canvas id="myCanvas" width="400" height="400">< /canvas>
< /body>
< /html>
渐变
渐变(gradient)是指从一种颜色向另一种颜色变化的填充,在颜色相交的地方做融合。在Canvas中你可以创建两种类型的渐变:线性的和径向的。
createLinearGradient()方法被用来创建线性的渐变。createLinearGradient(x0,y0,x1,y1)沿着一条由两个点(x0,y0)和(x1,y1)来标识的直线产生一个渐变,这两个点分别是渐变的起点和终点。该方法返回一个对象。
颜色的渐变可以有多种颜色,addcolorStop(offset, color) 方法为被标明为在给定的偏移量上渐变的颜色指明了颜色过渡点。addColorStop()方法让你在0和1之间指定一个偏移量,以这一偏移量为依据来开始过渡到下一种颜色。值0是渐变的一端的偏移量,1是另一端的偏移量。在颜色的渐变定义好了之后,渐变对象就可以被赋值给fillStyle()。你也可以使用fillText()方法来绘制出带有渐变的文字来。
径向渐变——createradialGradient(x0,y0,r0,x1,y1,r1)——使用六个参数以一种圆形或是圆锥形的模式来组合两种或多种颜色。
1. (x0,y0): 圆锥的第一个圆的中心
2. r0:第一个圆的半径
3. (x1,y1):圆锥的第二个圆的中心
4. r1:第二个圆的半径
图6包含了四种渐变:一个线性渐变、一个文本渐变、一个对角线上的渐变和一个径向渐变。
图6. 渐变的例子
图6的内容是使用清单5中的代码创建出来的。
清单5. 渐变的例子代码
< !doctype>图像剪裁
你可以通过裁剪出选定的区域来改变图像。在画布上裁剪是一项重载drawImage()方法的功能,drawImage()有三种选择,你可以使用三个、五个或者是九个参数。
三个参数的配置——drawImage(image, dx, dy)——在目标坐标(dx,dy)上绘制图形。坐标构成了图像的左上角。
五个参数的配置——drawImage(image, dx, dy, dw, dh)——提供了目标的宽度和高度,图像会被缩放以适应目标宽度和高度。
九个参数的配置——drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)——用到一个图像,以图像来源的(sx,sy)坐标为开始剪出一个宽度和高度为(sw,sh)的矩形区域,并把它缩放使之适应目标宽度和高度(dw,dh),然后把它放置在画布的(dx,dy)位置上。
图7显示了你将要对其做剪裁的图像。
图7. 剪裁图像
通过利用图7中给出的图像,可以把一组图像放置在画布上。一个图像有画布大小,被用作背景,另一个被创建的图像较小一些,被插入到画布的右下角上,第三个图像是一个切出来的拿破仑的头像,被放置在画布的左上角上。裁剪后的图像的最后情况如图8所示。
图8. 最终裁剪出来的图像
图8中的内容是使用清单6中的代码创建出来的。在执行这一代码之前,确保已下载了这一例子中用到的Napolean.png图像。
清单6. 用来裁剪例子图像的代码
< !doctype>
< html>
< head>
< title>Crop Example< /title>
< script type="text/javascript">
window.onload = function() {
var canvas=document.getElementById("cropNapolean");
var context=canvas.getContext("2d");
var imageObj = new Image();
imageObj.onload = function() {
// 绘制图像覆盖整个画布
context.drawImage(imageObj,0,0, 600, 400);
// 在右下角绘制一个小图像
var sourceX = 0;
var sourceY = 0;
var sourceWidth = 1200;
var sourceHeight = 801;
var destX = 300;
var destY = 200;
var destWidth = sourceWidth - 900;
var destHeight = sourceHeight - 600;
context.drawImage(imageObj, sourceX, sourceY, sourceWidth,
sourceHeight, destX, destY, destWidth, destHeight);
//只绘制拿破仑的头部
var sourceNapoleanX = 460;
var sourceNapoleanY = 25;
var sourceNapoleanWidth = 250;
var sourceNapoleanHeight = 175;
var destNapoleanX = 0;
var destNapoleanY = 0;
var destNapoleanWidth = sourceNapoleanWidth - 150 ;
var destNapoleanHeight = sourceNapoleanHeight - 100;
context.drawImage(imageObj, sourceNapoleanX, sourceNapoleanY,
sourceNapoleanWidth, sourceNapoleanHeight,
destNapoleanX, destNapoleanY,
destNapoleanWidth, destNapoleanHeight);
}
imageObj.src = "Napoleon.png";
}
< /script>
< /head>
< body>
< div>
< p>< canvas id="cropNapolean" width="600" height="400">< /canvas>< /p>
< /div>
< /body>
< /html>
动画和多重画布
要处理动画方面的内容的话,分层问题总是不可避免的。分层允许组件被隔开开来,这使得编码和调试变得更容易且更高效。Canvas API并未有分层的处理,但你可以创建多重的画布。
动画必须是随着时间的推移来做控制的,因此,要创建一个动画的话,你需要处理动画的每一帧内容。Canvas API在动画方面有一个主要的限制是:在某个形状被放置到画布上之后,它就一直保持它的样子不变了,要移动该形状的话,你必须要重新绘制它。
要创建一个动画的话:
1. 清除掉之前在画布上绘制的任何图像。
2. 保存画布的状态,确保在每次绘制一个帧的时候都是使用最初的状态。
3. 执行渲染帧的步骤。
4. 如果你已经保存了状态的话,在绘制新的帧之前恢复该状态。
你可以以两种方式来控制动画:使用setInterval或者setTimeout方法,每个方法都可以用来在超过某个设定时间段时调用一个函数。setInterval函数重复地执行所提供的代码,setTimeout函数只在所提供的时间过去之后执行一次。
图9展示了游泳者的多重画布动画的一帧,水画在一幅画布上,游泳的人则画在另一幅画布上。
图9. 用到多重画布的图像的动画
清单7中的代码被用来创建游泳者,代码使用一个线性渐变来创建水的效果。水有四种蓝色色调,这提供了一种合理的水的假象。游泳者的动作通过使用positionX和positionY的值来创建,这两个值改变图像所摆放的样子。游泳者的头使用arc()方法来创建,游泳者的腿和双臂则是通过绘制线段然后改变他们的lineTo()位置来创建,躯干则是通过修改moveTo()的位置来发生变化。因为这是一个动画,因此你需要执行这一段代码来看一下游泳者是如何运动的。
清单7. 动画例子
< !DOCTYPE HTML>
< html>
< head>
< title>Animation & Multiple Canvas Example< /title>
< script>
// 水的画布
function drawWater() {
var canvasWater = document.getElementById("myWaterCanvas");
var contextWater = canvasWater.getContext("2d");
contextWater.globalAlpha = .50 ;
// 创建一个线性渐变的填充
var linearGrad = contextWater.createLinearGradient(0,0,400,400);
linearGrad.addColorStop(0, '#0000ff'); // sets the first color
linearGrad.addColorStop(.25, '#0099ff'); // sets the second color
linearGrad.addColorStop(.50, '#00ccff'); // sets the third color
linearGrad.addColorStop(.75, '#00ffff'); // sets the fourth color
contextWater.fillStyle = linearGrad;
contextWater.fillRect(0,0,400,400);
}
// 游泳者的画布
setInterval(drawSwimmer, 30);
var positionX = 0;
var positionY = 0;
function drawSwimmer(){
var canvasSwimmer = document.getElementById("mySwimmerCanvas");
var contextSwimmer = canvasSwimmer.getContext("2d");
contextSwimmer.clearRect(0,0,400,400);
if (positionX < 30)
{
positionX += 1;
positionY += 1;
}
else
{
positionX = 0;
positionY = 0;
}
contextSwimmer.save();
// 绘制一个圆作为头部
var centerX = 200;
var centerY = 50;
var radius = 20;
contextSwimmer.beginPath();
contextSwimmer.arc(centerX, centerY+positionY,
radius, 0, 2 * Math.PI, false);
contextSwimmer.fillStyle = "#000000";
contextSwimmer.fill();
contextSwimmer.lineWidth = 5;
// 躯干部分
contextSwimmer.beginPath();
contextSwimmer.moveTo(200,70+positionY);
contextSwimmer.lineTo(200,175);
contextSwimmer.lineWidth = 10;
contextSwimmer.strokeStyle = "#000000";
contextSwimmer.lineCap = "round";
contextSwimmer.stroke();
// 画右边的手臂
contextSwimmer.beginPath();
contextSwimmer.moveTo(200, 100);
contextSwimmer.lineTo(175-positionX,140-positionY);
contextSwimmer.lineWidth = 10;
contextSwimmer.strokeStyle = "#000000";
contextSwimmer.lineCap = "round";
contextSwimmer.stroke();
// 画左边的手臂
contextSwimmer.beginPath();
contextSwimmer.moveTo(200, 100);
contextSwimmer.lineTo(225+positionX,140-positionY);
contextSwimmer.lineWidth = 10;
contextSwimmer.strokeStyle = "#000000";
contextSwimmer.lineCap = "round";
contextSwimmer.stroke();
// 画右边的腿
contextSwimmer.beginPath();
contextSwimmer.moveTo(200, 175);
contextSwimmer.lineTo(190-positionX,250-positionY);
contextSwimmer.lineWidth = 10;
contextSwimmer.strokeStyle = "#000000";
contextSwimmer.lineCap = "round";
contextSwimmer.stroke();
// 画左边的腿
contextSwimmer.beginPath();
contextSwimmer.moveTo(200, 175);
contextSwimmer.lineTo(210+positionX,250-positionY);
contextSwimmer.lineWidth = 10;
contextSwimmer.strokeStyle = "#000000";
contextSwimmer.lineCap = "round";
contextSwimmer.stroke();
contextSwimmer.restore();
};
< /script>
< /head>
< body onload="drawWater();">
< canvas id="myWaterCanvas" width="400" height="400" style="z-index: 2;
position:absolute;left:0px;top:0px;">
< /canvas>
< canvas id="mySwimmerCanvas" width="400" height="400" style="z-index: 1;
position:absolute;left:0px;top:0px;">
< /canvas>
< /body>
< /html>
结论
HTML5的画布是基于浏览器的RIA的结构核心,其提供了一种以JavaScript和你的想像力为驱动力的实用的绘图环境。学习它真的不是很难,并且网络上有许多培训和学习所需的支持工具,其中包括了速查表、博客、在线文章、视频和非视频教程,以及示例应用程序等。
可视化地修改文本和图像以及模拟运动的能力使得Canvas变成了一个极其有价值的工具,无论你是从设计者还是开发者的角度来熟悉它,无论你是使用Canvas来构建运行在移动设备上的游戏应用,还是仅仅想增强屏幕这一整体资源的利用情况,Canvas都是HTML5体验的重要组成部分。
?
参考资料
学习资料
1. “Create great graphics with the HTML5 canvas”(developerWorks,February 2011)是一个图形技术和处理的开发指南。
2. Safari Dev Center有一个名为Canvas Pixel Manipulation的演示,这是一个非常棒的使用画布来开发有效的视觉资产的例子。
3. WHATWG的HTML Living Standard为不断发展变化的HTML5 canvas规范的定制提供了一扇窗口。
4. W3Schools.com的HTML5 Canvas参考有几个可用来帮助你磨练画布方面的知识的练习。
5. MDM Docs的Canvas tutorial是一个很好的基础教程,该教程反映了Mozilla在开发方面的专业知识。
6. Let's Call It A Draw(ing Surface)是关于HTML5 canvas的基础理解的一个很有创意的熟习过程。
8. 随时在developerWorks technical events and webcasts 上关注各种IBM产品和IT行业主题。
9. 关注developerWorks on Twitter。
获取产品和技术
1. Dojo Toolkit这一开源的模块化JavaScript库有助于你快速地开发跨平台的基于JavaScript/Ajax的应用和网站。
2. 免费试用IBM软件,下载试用版,登录在线试用,在沙箱环境中使用产品,或是通过云来访问产品。有超过100个IBM试用产品可选择。
讨论
1. 现在就创建你的developerWorks个人资料,并设置一个关于HTML的观看列表。与developerWorks社区建立联系并保持联系。
2. 找到其他在web开发方面感兴趣的developerWorks成员。
3. 分享你的知识:加入一个关注web专题的developerWorks组。
4. Roland Barcia在他的博客中谈论Web 2.0和中间件。
5. 关注developerWork成员的shared bookmarks on web topics。
6. 快速获得答案:访问Web 2.0 Apps论坛。
7. 快速获得答案:访问Ajax论坛。
关于作者
Grace Walker是位于伊利诺斯州的芝加哥的Walker Automated Services公司的合伙人,她是一位有着多重背景和丰富经验的IT顾问。她在IT行业担任过经理、管理员、程序员、讲师、业务分析师、技术分析师、系统分析师和Web开发者,工作的背景环境也各不相同,其中包括了电信、教育、金融服务和软件等。