HTML5基础,第4部分:点睛之笔Canvas (2)



图4的显示——从左到右——为一条圆弧、一条二次曲线、一条贝塞尔曲线、一个半圆和一个圆。

图4. 圆弧、曲线和圆

HTML5基础,第4部分:点睛之笔Canvas (2)_第1张图片

图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. 使用转换

HTML5基础,第4部分:点睛之笔Canvas (2)_第2张图片

清单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. 渐变的例子

HTML5基础,第4部分:点睛之笔Canvas (2)_第3张图片

图6的内容是使用清单5中的代码创建出来的。

清单5. 渐变的例子代码

< !doctype>
< html>
< head>
< title>Gradient Example< /title>
< script>
window.onload = function() {
var canvas = document.getElementById("myCanvas");

var context = canvas.getContext("2d");

//在一个矩形中尝试做渐变

// 创建一个线性渐变 
var fillColor = context.createLinearGradient(50,50, 150,50);

// 设置渐变的颜色
fillColor.addColorStop(0.15,"red");
fillColor.addColorStop(0.35,"black");
fillColor.addColorStop(0.65,"green");
fillColor.addColorStop(0.87,"yellow");

// 把渐变对象赋值给fillstyle
context.fillStyle= fillColor;

// 绘制矩形
context.fillRect(50,50,100,100);

// 使用文本 

var fillColorText = context.createLinearGradient(300,50,600,50);

fillColorText.addColorStop(0.2,"red");
fillColorText.addColorStop(0.4,"black");
fillColorText.addColorStop(0.6,"green");
fillColorText.addColorStop(0.8,"yellow");

context.fillStyle= fillColorText;

context.font="40px verdana";
context.textBaseline="top";
context.fillText("With text too!", 300,50)

// 对角线上的渐变
var fillColordiagonal = context.createLinearGradient(50,200, 100,450);

// 渐变颜色
fillColordiagonal.addColorStop(0.2,"red");
fillColordiagonal.addColorStop(0.4,"black");
fillColordiagonal.addColorStop(0.6,"green");
fillColordiagonal.addColorStop(0.75,"yellow");

// 把渐变对象赋值给fillstyle
context.fillStyle= fillColordiagonal;

// 绘制矩形
context.fillRect(50,225, 100,250);

// 绘制径向渐变
fillColorRadial = context.createRadialGradient(450,300,0, 450,300,200);
fillColorRadial.addColorStop(0, "red");
fillColorRadial.addColorStop(0.2, "black");
fillColorRadial.addColorStop(0.4, "green");
fillColorRadial.addColorStop(0.7, "yellow");
context.fillStyle = fillColorRadial;
context.rect(300,200,500,400);
context.fill();

}
< /script>
< /head>
< body>
< div>
< p>< canvas id="myCanvas" width="600" height="400">< /canvas>< /p>
< /div>
< /body>
< /html>

图像剪裁

你可以通过裁剪出选定的区域来改变图像。在画布上裁剪是一项重载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. 剪裁图像

HTML5基础,第4部分:点睛之笔Canvas (2)_第4张图片

通过利用图7中给出的图像,可以把一组图像放置在画布上。一个图像有画布大小,被用作背景,另一个被创建的图像较小一些,被插入到画布的右下角上,第三个图像是一个切出来的拿破仑的头像,被放置在画布的左上角上。裁剪后的图像的最后情况如图8所示。

图8. 最终裁剪出来的图像

HTML5基础,第4部分:点睛之笔Canvas (2)_第5张图片

图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. 用到多重画布的图像的动画

HTML5基础,第4部分:点睛之笔Canvas (2)_第6张图片

清单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体验的重要组成部分

你可能感兴趣的:(html5,canvas)