WebGL 3D开发实战详解(第2版)
上QQ阅读APP看书,第一时间看更新

1.6 HTML5 Canvas简介

HTML5 Canvas是屏幕上由JavaScript控制的即时模式位图区域。即时模式是指在画布上呈现像素的方式,HTML Canvas通过JavaScript调用Canvas API,在每一帧中完全重绘屏幕上的位图。开人员需要做的就是在每一帧渲染之前设置屏幕的内容显示。

1.6.1 文档对象模型和Canvas

文档对象模型(DOM)代表了HTML页面上的所有对象,它是语言中立且平台中立的。它允许页面的内容和样式被Web浏览器渲染之后再次更新。用户可以通过JavaScript访问DOM。现在DOM已经成为JavaScript、DHTML和CSS开发中最重要的一部分。

画布元素本身可以通过DOM在Web浏览器中经由Canvas 2D环境访问。但是,在Canvas中创建的单个图形元素是不能通过DOM来访问的。正如本章前面讲到的,画布工作在即时模式,它并不保存自己的对象,只是说明在单个帧里绘制什么。

❑ 在使用Canvas之前大家需要了解两个DOM对象,其中一个对象为document,它包含所有在HTML页面的HTML标签上。

❑ 另一个对象window是DOM的最高一级,需要检测这个对象来确保在开始使用Canvas应用程序之前,已经加载了所有的资源和代码。

1.6.2 JavaScript与Canvas

用JavaScript来创建Canvas应用程序,程序能在现有的任何Web浏览器中运行。在使用JavaScript为Canvas编程时会有一个问题,在创建的页面中哪里为JavaScript程序的起点?有两种方式,一种为放在<head>标签中,另一种为放在<body>标签中。

❑ 将起点放在<head>元素中意味着整个HTML页面要加载完JavaScript才能配合HTML运行,在运行该程序前就必须检查HTML页面是否已经加载完毕。

❑ 另一种将起点放在<body>元素内的好处是,它可确保JavaScript运行时整个页面已经加载完毕。由于在运行Canvas程序前需要使用JavaScript测试页面是否加载,所以两种方法各有利弊。本书在编写的时候用的是第二种,读者可以选择自己喜欢的方式进行编程。

1.6.3 HTML5 Canvas版“Hello World”

现在来开发Canvas之路上的第一个案例,即Canvas版的“Hello World”。本节将从开发程序的第一步开始,一步步地将程序开发的过程呈现给大家,让没有开发经验的读者对开发程序有一个整体的概念。

在上一节中讲到了JavaScript与Canvas的关系。由于在开发本部分内容时html文件中难免会嵌入JavaScript脚本,所以我们第一步来看一下如何将JavaScript程序中的方法封装起来,并留下JavaScript程序的入口。

1.封装JavaScript代码

Canvas应用程序与浏览器中运行的其他应用有所不同。由于Canvas只在屏幕上的特定区域内执行并显示结果,可以说它的功能是独占的,因此不太会受到页面上其他内容的影响,反之亦然。读者如果想在同一个页面上放置多个Canvas应用,那么在定义时必须将对应代码分开。

为了避免出现这个问题,可以将变量和函数都封装在另一个函数中。JavaScript函数本身就是对象,JavaScript对象既可以有属性也可以有方法。将一个函数放到另一个函数中,读者可以使第二个函数只在第一个函数的局部作用域中。

        1    function eventWindowLoaded(){canvasApp(); }  //JavaScript程序在Canvas中的入口函数
        2    function canvasApp(){                        //入口函数需要调用的函数
        3        drawScreen();                            //绘制场景函数
        4        ……
        5        function drawScreen(){……                 //绘制函数,本程序中的重点
        6    }}

上述代码讲解了如何将JavaScript代码封装起来,封装好的方法只留下eventWindowLoaded()方法。在下一节中还将绘制不同图形的方法并放到外部文件中,在<head>标签部分加载这些文件,待到需要绘制时直接调用相应的方法即可。

2.将Canvas添加到HTML页面中

在HTML的<body>标签中添加一个<Canvas>标签时,可以参考下述代码。<canvas>标签有3个主要属性。大家都知道在HTML中,属性被设置在相应的标签中,id、width、height这3个属性分别代表JavaScript代码中用来指示特定<canvas>标签的名字、画布的宽度与高度。

        1    <canvas id="canvasOne" width="500" height="300">
        2    若看到这个文字,则说明浏览器不支持WebGL! </canvas>

在开始标签和结束标签中可以添加文本,一旦浏览器在执行HTML页面时不支持Canvas,就会显示这些文字。以本章的Canvas应用程序为例,这里使用的是“若看到这个文字,则说明浏览器不支持WebGL”。事实上此处可以随意放置文字。

接下来用DOM引用HTML中定义的<canvas>标签。document对象加载后可以引用HTML页面的任何元素。需要一个Canvas对象的引用,这样就能够知道当JavaScript调用Canvas API时其结果在哪里显示了。

        var  theCanvas=document.getElementById("canvasOne");

首先定义一个名为theCanvas的新变量,以保存Canvas对象的引用。接下来,通过调用document的getElementById()函数得到canvasOne的引用。canvasOne是在HTML页面中为创建的<canvas>标签定义的名字。

3.检测浏览器是否支持Canvas

现在已经得到了在HTML页面上定义的Canvas元素的引用,下面检测它是否包含环境。Canvas环境是指支持由Canvas的浏览器定义的绘图界面。简单地说,如果环境不存在,那么画布也不会存在。有多种方式可以对此进行验证。

这里使用的是modernizr.js库中的Modernizr,它是一个易用并且轻量级的库,可以检测各种Web技术的支持情况。Modernizr创建一组静态的布尔值,可以检测是否支持Canvas。在程序中已经包含modernizr.js,读者不用再自行下载了。

        1    <script src="modernizr.js"></script>
        2    function canvasSupport(){
        3        return Modernizr.canvas; }

上面代码第1行为将外部.js文件导入到HTML文件中,下面的代码是为了检测是否支持Canvas,而将canvasSupport()函数进行修改。这里将要使用modernizr.js方法,因此它提供了测试Web浏览器是否支持Canvas的最佳途径。

4.获得2D环境

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

最后需要得到2D环境的引用才能操作它。HTML5 Canvas被设计为可以与多个环境工作,包含一个建议的3D环境。不过这里只用到了2D环境。通过getContex()方法取得context,然后在之后的绘制函数中大家便可以用context来设置各个属性了。

5.绘制函数

现在可以创建实际的Canvas API代码了。在Canvas上运行的各种操作都要通过context对象,因为它引用了HTML页面上的对象。大家在案例中所看见的“屏幕”就是定义画布的绘图区域。首先应清空绘图区域。

        1    context.fillStyle="#ffffaa";
        2    context.fillRect(0,0,500,300);

上面的两行代码在屏幕上绘制出一个与画布大小相同的黄色方块。fillStyle()设置颜色,fillRect()创建一个矩形,并把它放到了屏幕上。在清空完绘图区域后,看一下绘制函数drawScreen()是如何开发的。

        1    function drawScreen(){
        2                context.fillStyle="#ffffaa";                 //背景
        3                context.fillRect(0,0,500,300);               //创建一个矩形
        4                context.fillStyle="#000000";                 //文字
        5                context.font="20px Sans-Serif";              //设置字体的大小和字号
        6                context.textBaseline="top";                  //设置字体的垂直对齐方式
        7                context.fillText("Hello World! ",195,80);    //将测试文本显示到屏幕上
        8                var helloWorldImage=new Image();             //添加2D图像
        9                helloWorldImage.onload=function(){
        10                    context.drawImage(helloWorldImage,155,110); }
        11               helloWorldImage.src="pic/helloworld.png";
        12               context.strokeStyle="#000000";              //设置边框
        13               context.strokeRect(5,5,490,290);
        14               }

❑ 第2~7行设置了背景颜色与形状,之后声明了文字的颜色、大小和字号并设置了字体的垂直对齐方式,最后将测试文本显示到屏幕上。

❑ 第8~13行为添加图形。为了将图像显示到画布上,需要创建一个Image()对象实例,并且将Image.src属性设为将要加载的图像名字。在显示图像之前,需要等待图像加载完毕。设置Image对象的onload函数可以为Imageload创建一个回调函数。

由于上面几节已将本例中的重点代码介绍了,所以就不再将全部代码在这里重写一遍了,读者可以查阅随书资源中的Sample1_23案例进行学习。下面来看一下第一个Canvas程序的运行效果,如图1-23所示。

图1-23 案例Sample1_23效果

读者在第一次开发时肯定会遇到一些问题,还会有调试程序的步骤。但是这里不会将可能的错误全部罗列出,读者在开发中遇到问题时可以用前面提到的浏览器自带调试器或者firebug进行调试。

学完Canvas版“Hello World”的开发过程后,大家来进一步深入学习一下Canvas提供的一些绘制基本图形的API。看完这些内容后读者就可以开发一些2D的内容了,这里提供的为系统的API,读者只要认真学习都可以掌握。

1.6.4 Canvas中的基础图形

在看完第一个Canvas程序后大家对它已有了基本认识,HTML5 Canvas的使用是以强大的绘图、着色和基本二维形状变换为基础的。然而,可供选择的内建形状相对有限,程序员可以通过一组称作路径的线段来绘制出想要的形状。

现在学习一下新的内容,在Canvas上绘制一些基本图形。绘制这些图形基本上都会有相应的API,本案例中不同的图形会在不同的JavaScript文件中,相应的API在里边都会有所体现。读者阅读时结合着注释便能够轻松学会,现在看一下这部分的开发过程。

代码位置:随书源代码/第1章目录下的HTML5/Sample1_24.html。

        1     <! DOCTYPE HTML>
        2     <html><head><title>Sample1_24</title>
        3     <script src="js/modernizr.js"></script>     //导入js文件夹下的modernizr.js文件
        4     <script src="js/arc.js"></script>            //导入js文件夹下的arc.js文件
        5     <script src="js/bezier.js"></script>        //导入js文件夹下的bezier.js文件
        6     <script src="js/line.js"></script>          //导入js文件夹下的line.js文件
        7     <script src="js/linejoin.js"></script>      //导入js文件夹下的linejoin.js文件
        8     <script src="js/rect.js"></script>          //导入js文件夹下的rect.js文件
        9     <script type="text/javascript">    //前面导入的为外部JavaScript文件,
              这里为内嵌的JavaScript文件
        10    var context;
        11    function eventWindowLoaded(){canvasApp(); } //封装加载JavaScript的方法
        12    function canvasSupport(){                   //检测浏览器版本是否支持Canvas
        13        return Modernizr.canvas; }
        14    function canvasApp(){                       //实际JavaScript的入口方法
        15        if(! canvasSupport()){return; }else{
        16               var theCanvas = document.getElementById("canvas");
        17               context=theCanvas.getContext("2d"); }
        18               drawScreen();    //绘制场景,不同的图形有不同的绘制方法,这里省略了其余的方法
        19               function drawScreen(){              //绘制2D图形的方法
        20               //画布背景色为白色,这不利于辨识,填充一个有颜色的区域便于标识
        21               context.fillStyle="#aaaaaa";       //设置背景样式
        22               context.fillRect(0,0,500,500);     //创建一个矩形
        23               context.fillStyle='#000000';          //文字
        24               context.font='20px _sans';             //文字的大小和字号
        25               context.textBaseline='top';            //设置文本垂直对齐方式
        26               context.fillText("Canvas! ",0,0); }}    //将测试文本显示到屏幕上
        27    </script></head>
        28    <body onload="eventWindowLoaded(); ">
        29    <div style="position: absolute; top: 50px; left:50px; ">
        30    <canvas id="canvas" width="500" height="500">
        31    若看到这个文字,则说明浏览器不支持WebGL! </canvas></div>
        32    </body></html>

❑ 第2~8行引入了各图形的JavaScript文件。每个图形的绘制方法都封装在了不同的文件中,在绘制时调用不同的绘制方法即可。读者在测试本案例时只需将drawScreen()方法替换掉便能测试不同的图形了。

❑ 第9~26行为内嵌的JavaScript脚本。这部分是Canvas程序的入口,其中Canvas的id通过context来设置一些属性,并且将绘图区域清屏并设置了一个与画布等大的矩形以显示Canvas画布。

❑ 第28~32行为创建Canvas的过程。具体过程在前面几节中已分别介绍了,onload在页面加载完毕后调用JavaScript脚本,Canvas设置好其3个属性。

在程序中调用drawScreen()方法时需要注意的是,在程序开头导入的几个JavaScript文件,这些文件包含绘制圆、直线、曲线的一些图形API,读者可以自行查阅这些代码进行学习,其中的解释和注意事项在注释中都有详细介绍,这里便不再赘述。

HTML5 Canvas这里便介绍完毕,读者千万别以为就已经掌握了Canvas, Canvas是HTML5新增的元素,可以干的事情还有很多。本章只介绍了2D环境下的绘制图形,以后的章节才是Canvas的真正应用。