第一章 基础知识
第五节 基本的绘制操作
在下一章中,将详细讲述canvas的绘制。现在,为了让读者熟悉一下Canvas所提供的绘图API方法,所以咱们先来看看图1-13中的这个程序,它是一个带指针的时钟(analog clock)。
该时钟的代码列在程序清单1-4之中,它用到了如下的Canvas绘图API:
·arc()
·beginPath()
·clearRect()
·fill()
·fillText()
·lineTo()
·moveTo()
·stroke()
像Adobe Illustrator与Apple的Cocoa框架那样,Canvas也可以让开发者先创建不可见的路径,稍后再调用stroke()来描绘路径的边缘,或者调用fill()来对路径的内部进行填充,使路径变得可见。可以调用beginPath()方法来开始定义某一段路径。
在时钟应用程序的代码中,drawCircle()方法绘制了一个表示钟面的圆形,该方法先调用beginPath()来开始定义路径,然后再调用arc()来创建一个圆形的路径。等到应用程序的代码调用了stroke()方法之后,刚才定义的路径才会变得可见。与之类似,该程序的drawCenter()方法也是通过组合调用beginPath()、arc()与fill()这几个方法来绘制时钟中心的那个小实心圆的。
该应用程序的drawNumerals()方法通过调用fillText()来绘制钟面周围的数字,fillText()这个方法是用来在canvas中进行文本填充的。与arc()方法不同,fillText()方法并不会创建路径,而是立即将文本渲染到canvas之上。
钟表的指针则是通过应用程序代码中的drawHand()方法来绘制的。该方法调用了如下三个用于绘制线段方法将钟表指针绘制出来:moveTo()、lineTo()与stroke()。先调用moveTo()方法将画笔(graphics pen)移动到canvas中的指定地点,然后调用lineTo()方法,在该点与另外一个指定的点之间绘制一条不可见的路径,最后使用stroke()方法将当前路径变为可见。
应用程序通过调用setInterval()方法来制作时钟的动画效果。该方法每秒钟都会调用一次drawClock()函数。而后者则使用clearRect()方法来擦除canvas,然后再重绘时钟。
程序清单1-4 一个基本的时钟程序
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d'),
FONT_HEIGHT = 15,
MARGIN = 35,
HAND_TRUNCATION = canvas.width/25,
HOUR_HAND_TRUNCATION = canvas.width/10,
NUMERAL_SPACING = 20,
RADIUS = canvas.width/2 - MARGIN,
HAND_RADIUS = RADIUS + NUMERAL_SPACING;
//Functions..........................................................
function drawCircle() {
context.beginPath();
context.arc(canvas.width/2, canvas.height/2,
RADIUS, 0, Math.PI*2, true);
context.stroke();
}
function drawNumerals() {
var numerals = [ 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12 ],
angle = 0,
numeralWidth = 0;
numerals.forEach(function(numeral) {
angle = Math.PI/6 * (numeral-3);
numeralWidth =context.measureText(numeral).width;
context.fillText(numeral,
canvas.width/2 + Math.cos(angle)*(HAND_RADIUS) -
numeralWidth/2,
canvas.height/2 + Math.sin(angle)*(HAND_RADIUS) +
FONT_HEIGHT/3);
});
}
function drawCenter() {
context.beginPath();
context.arc(canvas.width/2, canvas.height/2,5, 0, Math.PI*2, true);
context.fill();
}
function drawHand(loc, isHour) {
var angle = (Math.PI*2) * (loc/60) -Math.PI/2,
handRadius = isHour ? RADIUS -HAND_TRUNCATION-HOUR_HAND_TRUNCATION
: RADIUS -HAND_TRUNCATION;
context.moveTo(canvas.width/2,canvas.height/2);
context.lineTo(canvas.width/2 +Math.cos(angle)*handRadius,
canvas.height/2 +Math.sin(angle)*handRadius);
context.stroke();
}
function drawHands() {
var date = new Date,
hour = date.getHours();
hour = hour > 12 ? hour - 12 : hour;
drawHand(hour*5 + (date.getMinutes()/60)*5,true,0.5);
drawHand(date.getMinutes(), false,0.5);
drawHand(date.getSeconds(), false,0.2);
}
function drawClock() {
context.clearRect(0,0,canvas.width,canvas.height);
drawCircle();
drawCenter();
drawHands();
drawNumerals();
}
//Initialization................................................
context.font = FONT_HEIGHT + 'px Arial';
loop = setInterval(drawClock, 1000);
提示:进一步研究路径、描边与填充
本节的时钟范例程序展示了canvas图形绘制的概况,在第2章之中,我们将详细地研究如何在canvas中进行图形的绘制与处理。