[HTML5基础,第4部分:点睛之笔Canvas]点睛之笔
(译者注:由于yeeyan编辑器对文章中的标签做解析的原因,我在每个标签的<符号之后都加入了一个空格,比如说,左尖括号<+head+右尖括号>,我会写成< head>,以便其能够在文章中正确显示,不便之处敬请谅解。)
使用HTML5来编写代码的人,有着设计者和开发者双重身份的强悍组合,其职责是构造出高效的富互联网应用(rich Internet application,RIA),特别是丰富的用户界面。就高效这个字眼来说,我的意思是指系统级的和系统性的创造力增强,这种增强以数字化的方式促进了站点所有者、所有者的代理机构和站点用户之间的对话。
RIA是用户获得满意体验的来源之处和媒介,因此,它是任何成功的以网络为中心的风险投资的重要组成部分。以网络为中心的活动,就性质来说,或多或少都是协作式的。公司要在包括了市场营销和管理的各个层面都取得成功的话,数字化协作的制胜方法是至关重要的。很多时候的很多情况都取决于效率,网站要依靠效率来满足其访问者的品质期望。
正如你已经见到的那样,HTML5是为这一具有跨平台能力、融合了通信、使用统一语言、提供无处不在的计算,以及基于开放系统的协作式“一网化世界(one web world)”量身定做的。这一文章系列的前面三部分内容重点关注语义、正确的编码方法、输入在极为重要的转化过程中的作用,以及站点管理最佳做法等,所有这些的目的都是在为以一种有组织和符合逻辑的方式来创建RIA奠定基础。每篇文章中都共有的一个主题是,对于实现网站所有者的机构目标来说,制造并管理丰富的用户体验是至关重要的。
什么是Canvas?
HTML5 Canvas(画布)是一个非常有用的绘图和动画元素,Canvas使用JavaScript来直接在页面上绘制图形。这是一个由你来定义和控制的长方形区域,该区域允许动态、可脚本渲染的2D图形和位图图像。
在制作用来增强UI、示意图、相册、图表、图形、动画和嵌入式绘图应用的那些非常棒的视觉材料方面,HTML5堪称完美。Canvas元素有一些用来绘制路径、矩形、圆形和字符的方法。
Canvas的坐标
在画布上绘图的一个先决条件是要熟悉网格或是坐标空间,宽度和高度的空间区域测量是以像素为单位给出的。画布是基于x和y坐标的使用来构建的,画布的x=0, y=0坐标位于左上角。
画布的矩形区域的默认属性是300像素的宽度和150像素的高度,但你可以通过指定宽度和高度来确定画布元素的确切大小。图1中的示意图说明了x和y坐标的实现方式。
图1. 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. 线条
2. 矩形
3. 圆弧
4. 贝塞尔曲线和二次曲线
5. 圆和半圆
你会用到的Canvas效果包括:
1. 填充和描边
2. 线性和径向的渐变
要讨论的转换包括:
1. 缩放
2. 旋转
3. 平移
绘制线段
要在画布上绘制线段的话,你可以使用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>
< 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. 剪裁图像
通过利用图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体验的重要组成部分。
- [HTML5基础,第4部分:点睛之笔Canvas]点睛之笔 相关文章:
- [HTML5,Canvas中使用路径描画二阶、三阶贝
在HTML5Canvas中,可以用以下方法描画三阶和二阶的贝塞尔曲线:代码如下:context be...
- 爱情文章
- 亲情文章
- 友情文章
- 随笔
- 哲理
- 励志
- 范文大全
-
小米电视恢复出厂设置 [小米电视怎么恢复出厂设置教程?]
现在很多人买小米系列产品,现在小米电视卖的也很好,那么小米电视怎么恢复出厂设置教程?下面分享小米电视
【爱情文章】 日期:2020-02-16
-
美团拍店怎么做任务? 美团众包拍店任务什么意思
美团拍店是美团旗下数据采集APP,小伙伴可以通过做任务赚取奖励!随手拍下门店照片电话等即可赚钱哦!那
【爱情文章】 日期:2020-04-19
-
【魅族Pro5通话中如何查看联系人?】通话中查找联系人
当别人打电话给你询问他人的电话号码时,你还在手机上查看后再回拨或短信告知?接下来,大猫教你魅族Pro
【爱情文章】 日期:2020-04-16
-
BIOS参数无法进行设置:蚂蚁保护板参数无法设置
在进入BIOS设置后,无法修改设置的数据,导致这种情况的原因有很多种,各种情况处理方法也不同。1 设
【爱情文章】 日期:2020-04-05
-
小米手机如何批量删除联系人 小米手机如何批量删除联系人(适应
在网上看到很多刚用小米手机的朋友不知道小米手机怎么批量删除联系人,小米手机小米2、小米3、红米等等都
【爱情文章】 日期:2020-02-23
-
苹果iPhone6S开机菜单导航关闭方法 iPhone 6S
苹果iPhone6S开机菜单导航关闭方法。手机每次重启后就会出现“开机菜单导航&rdqu
【爱情文章】 日期:2020-04-16
-
vivo手机怎么设置闹钟背景图片【闹钟ONE怎么更换提醒界面背景图
很多小伙伴都不喜欢闹钟ONE系统默认的背景图片,不喜欢的话可以更换掉,那么怎么更换背景图片呢?现在小
【爱情文章】 日期:2020-04-07
-
[Word表格中内容太多不能全部显示该怎么设置?]表格内容太多不显示
在处理Word表格的时候,我们难免遇到这样的情况:即:表格单元格的文字太多,以至于该单元格无法显示全
【爱情文章】 日期:2020-04-26
-
Win8如何卸载自带播放器 360视频默认播放器
1、使用组合键win+i打开选择“控制面板”2、在控制面板的界面中在右上方的查看方式更改为“小图标”
【爱情文章】 日期:2020-03-15
-
支付宝转送福气卡没收到怎么办|小米旗舰店送福气包
支付宝转送福气卡没收到怎么办问题详情:支付宝转送福气卡,福气一直显示赠送中,好友没有收到,而自己的福
【爱情文章】 日期:2020-03-31
-
【jsp页面中插入css样式的三种方法总结】 在jsp中怎样加入css样式
本篇文章主要是对jsp页面中插入css样式的三种方法进行了总结介绍,需要的朋友可以过来参考下,希望对
【亲情文章】 日期:2020-05-29
-
室内设计原则 室内设计的原则有哪些
(一)室内装饰设计要满足使用功能要求室内设计是以创造良好的室内空间环境为宗旨,把满足人们在室内进行生
【亲情文章】 日期:2018-08-08
-
【在matlab中同一个窗口绘制多个曲线】 matlab绘制曲线的方法
matlab中绘制二维图形有一个能在同一个坐标下绘制多个图案的功能。plot(x1,y1,x2,y2
【亲情文章】 日期:2020-05-29
-
家居防潮法则之客厅篇_客厅颜色搭配法则
防潮第一步从客厅开始,绝对是最明智的选择。试想在阴雨连绵的天气,大部分人必定选择宅在家里,那么客厅就
【亲情文章】 日期:2018-08-09
-
耐用经济窗帘杆的挑选方法_窗帘杆的价格
在现代家居软装饰中,窗帘的功能已不仅仅是有遮挡阳光的功能,更重要的是窗帘能很好衬托居室的装饰风格,窗
【亲情文章】 日期:2018-08-09
-
autoCAD,2007坐标系的建立方法图解:三坐标测量仪怎么建立坐标系图解
适用于:autocad2004、autoCAD2007方法:1、打开cad软件,在cad里绘制一个矩
【亲情文章】 日期:2018-08-08
-
三星s4三种截屏小技巧总有一种适合你 华为截屏小技巧
很多时候,我们在使用手机的时候需要截屏,但是又不知道怎么做。在这里,小编给大家带来三星s4截屏方法。
【亲情文章】 日期:2020-02-12
-
[i5-4690配GTX770显卡实现高端DIY装机图文直播全过程,附配置清单
很多玩家为了提高电脑的性能,选择了自己搭配硬件进行电脑组装,今天教程网小编为大家带来一套定位2015
【亲情文章】 日期:2020-02-11
-
小度wifi插入电脑USB接口后没反应该怎么反应?_小度wifi多少钱一个
wifi是手机上网必备的伙伴,办公室没WIFI,买了个小度wifi使用几天后,插入接口窗口显示:未插
【亲情文章】 日期:2020-02-12
-
机箱前置usb30接主板哪个口_怎么分清电脑主板前置机箱接线?,连接
教你认清主板前置机箱接线,连接主板跳线,装电脑连跳线就这几步,简单吧1、电源开关(POWER)这个开
【亲情文章】 日期:2020-02-09
-
【支付宝小视频如怎么保存?】 支付宝小视频怎么保存到相册
对于今天推出的最新支付宝9 2版本中,支付宝给我们新增了小视频功能,可以实现10秒视频拍摄,这点跟微
【友情文章】 日期:2020-05-05
-
怎么按成绩分班 [巧用WPS快速进行自动分班操作]
前言:分班是教学管理信息化的一个热门话题,一般要用专门的软件,经过试验,用手头上的WPS电子表格,不
【友情文章】 日期:2020-02-29
-
养乐多最短的广告词 养乐多广告语
养乐多广告语:1一百亿个活的养乐多菌帮肠道做运动,肠子漂亮,人就美,活的活的养乐多,越活越开心。2给
【友情文章】 日期:2020-03-16
-
【支付宝删除本地证书和取消证书的区别是什么?】 支付宝电脑版
删除本地证书:可以防止他人用证书登录进行操作。删除后仍然是证书用户,只是把当前机器中安装的证书删除了
【友情文章】 日期:2020-04-07
-
十三步简单入侵个人电脑教程:如何简单入侵苹果手机
木马冰河是一款功能强大的远程控制软件,因为它的功能很强大所以成为了黑客们发动入侵的工具,2HK联盟M
【友情文章】 日期:2020-03-14
-
[一起作业怎么刷学豆]一起作业无限学豆软件
一起作业怎么刷学豆?一起作业怎么得学豆?一起作业是一款非常好用的帮助孩子学习的教育学习平台,在一起作
【友情文章】 日期:2020-03-27
-
店铺跳失率多少正常【淘宝店铺跳失率高怎么解决】
1 首页布局没有根据人群浏览习惯吸引买家眼球浏览更多的屏幕数,首页跳失率高;我们都知道淘宝店铺首页装
【友情文章】 日期:2020-03-05
-
交换机电源出现问题:交换机需要电源吗
一些外部的因素,会导致交换机不能正常工作,比如外部的供电不稳定、电源线路有问题等。而且还会由于电源问
【友情文章】 日期:2020-04-07
-
范冰冰的直播号是多少【花椒直播范冰冰直播间id是多少】
花椒直播已经和范冰冰正式签约!范爷将担任花椒直播首席体验官!那么范冰冰花椒直播间id是多少。范冰冰花
【友情文章】 日期:2020-03-07
-
电脑上做美篇图片怎么添加 电脑上的图片显示不了,用美图看看可
很多电脑用户都会遇到这样的问题,那就是电脑上的图片显示不了,可能很多网友会选择放弃这个图片,或者重新
【友情文章】 日期:2020-03-14
-
【清除顽固病毒的方法】 怎样删除电脑顽固病毒
有些病毒非常的顽固,在删除后等你重启电脑,它又来了,一起看看清除顽固病毒的方法。一、清空Intern
【生活随笔】 日期:2020-05-29
-
Redmine+SQL,SERVER在Windows下的安装 Windows下安装grub
我们一直用Redmine做管理项目和系统缺陷跟踪 最近中心开发了微信平台,并引入了电话系统,都是SQ
【生活随笔】 日期:2020-05-29
-
【CPU超频所导致的电脑系统蓝屏的有效解决方法】CPU超频
CPU超频容易损坏硬件,影响CPU的寿命。但是对于许多电脑发烧友来说,超频可以在已有的硬件基础上花少
【生活随笔】 日期:2020-02-09
-
浜崎真绪所有作品百度云盘_360云盘手机版想分享视频给所有朋友怎
可以使用云盘朋友圈,选择发送给所有的好友,这样他们都可以看到了,直是简单方便呢。图示:
【生活随笔】 日期:2020-04-07
-
【卧室床单搭配术】卧室床单适合什么颜色
众所周知,卧室是提供家人休息、睡觉的场所,其装修设计应追求舒适与宁静。随着人们生活品质生活的提升,如
【生活随笔】 日期:2018-08-09
-
【诠释LED显示屏控制系统之异步控制方式】 LED显示屏控制系统
LED显示屏控制方式有两种,一是同步控制方式,二是异步控制方式。同步控制方式是指:LED屏同步显示电
【生活随笔】 日期:2018-08-09
-
[三星UA55ES8000有网络端口(LAN)端口吗]三星UA55ES800
三星UA55ES8000有1个网络端口(LAN)端口。
【生活随笔】 日期:2020-03-22
-
非阿里巴巴集团网站购物流程_免税店购物流程
1以美团网为例,各网站实际操作流程会有不同,请以实际操作页面提示为准。如:打开美团网(),找到需要购
【生活随笔】 日期:2020-04-10
-
【怎么让美食显得更加诱人的拍摄技法】 彩蛋技法
古代皇帝用膳先得请一个人先替自己尝两口,等别人吃完过一会儿一看没事,好,这菜没被下毒,这就可以放心吃
【生活随笔】 日期:2020-03-18
-
PhotoShop制作泼墨山水风景画_水彩风景画详细步骤图
中国画以水调墨,在生宣纸上用墨色的浓淡变化绘出美丽的画面。下面我们用Photoshop将一幅照片处理
【生活随笔】 日期:2020-04-05
-
[serverx病毒怎么清理] 一键手机清理应用
第一步:开始--运行输入regedit确定进入注册表删除如下项:[HKEY_CURRENT_USER
【人生哲理】 日期:2020-05-29
-
cpu的风扇1155针与775针有什么区别? cpu和风扇都要涂硅脂吗
cpu的风扇1155针与775针有什么区别?775的4个脚的距离是7 2CM,1155的4个脚的距离
【人生哲理】 日期:2020-02-09
-
艺术字体图片 转换器 [使用彩影实现炫酷字体倒影特效]
倒影特效在很多地方都会用到,比如个人相片注释、产品展示、标题设计、网页图片、广告等。今天小编将向大家
【人生哲理】 日期:2020-05-29
-
手绘一级减速器装配图 浩辰CAD机械教程之减速器主视图绘制
在前几期的CAD教程中,我们为大家介绍了使用浩辰CAD机械2011绘制二级齿轮减速器装配图的部分技巧
【人生哲理】 日期:2018-08-08
-
电视出镜记者的运用技巧和误区【杀毒技巧及6大杀毒误区】
一、一般方法1、请升级你的杀毒软件到最新版本,保证病毒库是最新的。2、对于联网的用户,在杀毒之前请断
【人生哲理】 日期:2020-05-29
-
3d模型的黑色背面怎么变成透明_怎么把图片黑色全部变成透明
我们在单面建立前面模型的时候是希望悲鸣能透明,而不挡住后面的模型。1:建立我们需要的单面墙体,然后给
【人生哲理】 日期:2018-08-08
-
[浩辰建筑教程之轴号编辑(添补、重排、倒排轴号)]添补轴号
使用浩辰建筑软件轴网绘制和轴网标注好后,轴号有时候还需要进行处理。譬如:增加轴号,倒排轴号,或轴号的
【人生哲理】 日期:2018-08-08
-
中兴Z9,Max/Z9,Mini开箱测评:中兴手机刷机教程图解
为了满足消费者的不同需求,不少手机厂商都推出了尺寸各异的设备。3月下旬的时候,中兴在北京演艺中心召开
【人生哲理】 日期:2020-02-16
-
CAD绘制璀璨的钻石戒指:CAD钻石
这篇教程教三联的朋友们用AutoCAD绘制璀璨的钻石戒指,教程难度不大。转发过来和三联的朋友们一起学
【人生哲理】 日期:2018-08-08
-
【路由器死机的四大原因分析】 路由器桥接设置图解
经常会在网上看到诸多网友在购买宽带路由器以后,在使用过程中遇到死机频繁掉线问题,给网友带来很多不便,
【人生哲理】 日期:2020-02-16
-
Apple,Watch在表盘上添加文字与符号的方法:小车表盘上符号
很多苹果手表AppleWatch的用户都知道怎么更换表盘的图片,那么,大家知道怎么在表情上显示自己的
【励志文章】 日期:2020-03-19
-
AMD,760K与AMD,860K哪个好?AMD速龙ii,X4,860K和760K区别对比介绍|AMD速龙IIX4
近日AMD推出了新一代屏蔽核显,可超频的AMD速龙iiX4860k四核处理器,该处理器主要用户取代上
【励志文章】 日期:2020-02-09
-
美团怎么买学生票 美团团购怎么购买学生票
接下来小编就教大家美团团购购买学生票方法。1)打开美团团购进入应用后【向左拨动】功能栏,接着点击【火
【励志文章】 日期:2020-04-15
-
[H5广告的4个困境]广告字牌 困境
你有没有突然对现在市面上H5开始麻木了,形势千篇一律,内容缺乏新意?自己想做却总做不出像样的,不知道
【励志文章】 日期:2020-05-08
-
监控sd卡显示不存在 安卓手机sd卡不存在是什么原因
1、请确保你的手机中装有SD卡,且SD卡无损坏;2、请确保你的SD卡接触良好,在“设置-
【励志文章】 日期:2020-05-21
-
手机文件怎么上传到钉盘【钉钉如何在钉盘中设置上传的文件其他人
无法设置,隐私文件可以放到企业群文件夹中,只要企业群成员才可以查看;
【励志文章】 日期:2020-04-10
-
12308汽车票 [12308汽车票包车方法]
12308汽车票包车方法。想要多人结伴去游玩?或者想要同伴一起回家?一起来包车吧!时间方面更自由。那
【励志文章】 日期:2020-04-07
-
我的咖啡学习过程 mcafee mcafee,8.5i,安装过程中出现McAfee,F
确认有足够的权限启动系统服务。”按“忽略(I)”才能继续安装,但最后还是不能升级。经过不断摸索,上官
【励志文章】 日期:2020-03-29
-
【利用wps文字制作一张漂亮的座位表】如何用wps制作座位表
在如今的生活年代里,学校教室,体育赛场,公司会议,演唱会,晚会,聚会,乘车坐船等很多场所,常常涉及到
【励志文章】 日期:2020-05-25
-
【宝贝主图帮助拉动流量】 站外投放如何进行拉动流量
如果说你有去亲自去搜索过淘宝你想要的产品话,那你就要想想在一大堆产品里面吸引你去点击的主图是什么样的
【励志文章】 日期:2020-05-29
-
2022年度年党史学习教育专题民主生活会相互批评意见60条
1、服务中心的意识还需进一步提高。比如在统战工作如何进一步汇集各方力量,服务推动X高质量发展上,方法不多,成效不够明显。2、在一抓到底狠抓落实上还需加强。对于影响稳定...
【范文大全】 日期:2024-05-03
-
高二读书心得体会推荐3篇
高二读书心得体会推荐3篇高二读书心得体会推荐篇1最近,我读了一本名叫《钢铁是怎样炼成的》一本书,读完
【范文大全】 日期:2024-05-03
-
党史学习教育专题党课主持词范本五篇(全文完整)
一百年来,中国共产党带领中国人民进行的一切奋斗、牺牲、创造,归结起来就是一个主题:实现中华民族伟大复兴。下面是范文网小编为您推荐2021精选党史学习教育专题党课主持词...
【范文大全】 日期:2024-05-03
-
2022年度社会创新中心年度工作要点
一、以党建为统领,夯实社会组织党建群团工作一是全力构筑社会组织的发展堡垒。结合社会组织党建工作实际,调整完善社会组织综合党委、联合工会、综合妇联、联合团委的领导班...
【范文大全】 日期:2024-05-03
-
儿童节活动开幕主持词五篇大全【优秀范文】
主持人在台上表演的灵魂就表现在主持词中。在当下的中国社会,主持词在各种活动中起到的作用越来越大,主持要好好准备自己的主持词,以下是范文网小编为您推荐。 儿童...
【范文大全】 日期:2024-05-03
-
幼儿园优秀教师演讲稿4篇
幼儿园优秀教师演讲稿4篇幼儿园优秀教师演讲稿篇1尊敬的各位领导、各位老师:我是一名普普通通的幼儿教师
【范文大全】 日期:2024-05-03
-
2022年党委书记述责述廉报告
市委:本人于xx年x月就任xx工作委员会书记。园区党工委是市委派出机构,对园区全面从严治党负主体责任,本人是第一责任人。根据《中国党内监督条例》、市委《关于加强对各级党...
【范文大全】 日期:2024-05-03
-
2022年同学聚会男女主持词五篇(精选文档)
主持词种类主持词大体上可分为会议主持词、文艺演出晚会主持词、赛事活动主持词、节庆活动主持词、婚庆礼仪主持词等。以下是范文网小编为您推荐。 公司举办活动主持词1...
【范文大全】 日期:2024-05-03
-
2022年度儿童生日晚会主持词五篇大全(2022年)
要增加主持词的文化内涵,达到寓教于乐的主持词的写作,在不增加篇幅的情况下,应尽量增加文化内涵,寓教于乐,不断提高观众的文化知识和素养。以下是范文网小编为您推荐。 ...
【范文大全】 日期:2024-05-03
-
2022年度办事处工会联合会年工作总结(街道)(完整)
2021年工会根据xx区总工会的工作部署,坚持以***新时代特色社会主义思想为指导,认真学习*********精神,紧紧围绕中心工作,以服务职工为重点,充分发挥工会桥梁、纽带作用,...
【范文大全】 日期:2024-05-03