学习第十天(2019-11-23)

第十五章 使用Canvas绘图

HTML5添加的<canvas>元素负责在页面中设定一个区域,然后就可以通过JavaScript动态地在这个区域中绘制图形。      如:<canvas id="drawing" width=" 200" height="200">A drawing of something.</canvas> 

在使用<canvas>元素之前,首先要检测getContext()方法是否存在,这一步非常重要。有些浏览器会为HTML规范之外的元素创建默认的HTML元素对象。在这种情况下,即使 drawing 变量中保存着一个有效的元素引用,也检测不到 getContext()方法。

一、使用2D上下文

    使用2D绘图上下文提供的方法,可以绘制简单的2D图形,比如矩形、弧线和路径。2D上下文的坐标开始于<canvas>元素的左上角,原点坐标是(0,0)。所有坐标值都基于这个原点计算,x值越大表示越靠右,y值越大表示越靠下。默认情况下,width和height表示水平和垂直两个方向上可用的像素数目。 

1、填充和描边 

   填充和描边两个操作取决于两个属性:fillStyle 和 strokeStyle。这两个属性的值可以是字符串、渐变对象或模式对象,而且它们的默认值都是"#000000"。

2、绘制矩形

  与矩形有关的方法包括 fillRect()、 strokeRect()和 clearRect()。

   fillRect()方法在画布上绘制的矩形会填充指定的颜色,填充的颜色通过fillStyle属性指定;strokeRect()方法在画布上绘制的矩形会使用指定的颜色描边,描边颜色通过strokeStyle属性指定,clearRect()方法用于清除画布上的矩形区域。

   下面是一个例子:

1 <html>
2 <head> 
3 <script type="text/javascript" src="myscript.js"></script>
4 </head>
5 <body>
6 <canvas id="drawing" width=" 200" height="200">A drawing of something.</canvas>
7 </body>
8 </html>
 1 window.onload = function(){
 2    var drawing = document.getElementById("drawing"); 
 3 //确定浏览器支持<canvas>元素 
 4    if(drawing.getContext){ 
 5       var context = drawing.getContext("2d");
 6       //绘制红色矩形  
 7       context.fillStyle = "#ff0000";
 8       context.fillRect(10, 10, 50, 50);
 9       //绘制半透明的蓝色矩形
10       context.fillStyle = "rgba(0,0,255,0.5)";
11       context.fillRect(30, 30, 50, 50); 
12       //绘制黑色描边矩形
13       context.strokeStyle = "#000000";     
14       context.strokeRect(10, 10, 50, 50); 
15       //绘制半透明的绿色描边矩形
16       context.strokeStyle = "rgba(0,255,0,0.5)";
17       context.strokeRect(30, 30, 50, 50);
18       //在两个矩形重叠的地方清除一个小矩形
19       context.clearRect(40, 40, 10, 10); 
20    } 
21 }

效果图:

 3、绘制路径 

    要绘制路径,首先必须调用beginPath()方法,然后可调用其他方法绘制路径,常用方法(省略了参数):arc()、arcTo()、bezierCurveTo()、lineTo()、moveTo()、quadraticCurveTo()、rect()。

  如绘制一个不带数字的时钟表盘:

 1 window.onload = function(){
 2    var drawing = document.getElementById("drawing");  
 3    //确定浏览器支持<canvas>元素
 4    if(drawing.getContext){ 
 5        var context = drawing.getContext("2d"); 
 6        //开始路径
 7        context.beginPath(); 
 8        //绘制外圆
 9        context.arc(100, 100, 99, 0, 2 * Math.PI, false); 
10        //绘制内圆
11        //在绘制内圆之前,须把路径移动到内圆上的某一点,避免绘制出多余的线条。
12        context.moveTo(194, 100);
13        context.arc(100, 100, 94, 0, 2 * Math.PI, false); 
14        //绘制分针
15        context.moveTo(100, 100);
16        context.lineTo(100, 15); 
17        //绘制时针
18        context.moveTo(100, 100);
19        context.lineTo(35, 100);  
20        //描边路径 
21        context.stroke();
22    } 
23 }

效果图:

4、绘制文本 

  绘制文本主要有两个方法:fillText()和strokeText()。这两个方法都可以接收4个参数:要绘制的文本字符串、x坐标、y坐标和可选的大像素宽度。

  由于绘制文本比较复杂,特别是需要把文本控制在某一区域中的时候,2D上下文提供了辅助确定文本大小的方法measureText()。这个方法接收一个参数,即要绘制的文本,返回一个TextMetrics 对象。返回的对象目前只有一个 width 属性,但将来还会增加更多度量属性。

  measureText()方法利用 font、textAlign和textBaseline的当前值计算指定文本的大小,假如想在一个140像素宽的矩形区域中绘制文本Hello world!,下面的代码从100像素的字体大小开始递减,最终找到合适的字体大小。

1 var fontSize = 100; context.font = fontSize + "px Arial";  
2 while(context.measureText("Hello world!").width > 140){
3      fontSize--;
4      context.font = fontSize + "px Arial";
5 } 
6 context.fillText("Hello world!", 10, 10);
7 context.fillText("Font size is " + fontSize + "px", 10, 50); 

5、变换

通过上下文的变换,可以把处理后的图像绘制到画布上。常用方法: 

rotate(angle):围绕原点旋转图像 angle 弧度;
scale(scaleX, scaleY):缩放图像;
translate(x,y):将坐标原点移动到(x,y);
transform(m1_1, m1_2, m2_1, m2_2, dx, dy):直接修改变换矩阵,
setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy):将变换矩阵重置为默认状态,然后再调用transform()。

 例如:可以把原点变换到时钟表盘的中心点(100,100),所有数学计算都基于(0,0),而不是(100,100)。还可以使用 rotate()方法旋转时钟的表针。 

 代码如下:

 1 window.onload = function(){
 2    var drawing = document.getElementById("drawing"); 
 3 //确定浏览器支持<canvas>元素
 4    if(drawing.getContext){ 
 5      var context = drawing.getContext("2d"); 
 6      //开始路径
 7      context.beginPath();  
 8      //绘制外圆
 9      context.arc(100, 100, 99, 0, 2 * Math.PI, false);  
10      //绘制内圆
11      context.moveTo(194, 100);
12      context.arc(100, 100, 94, 0, 2 * Math.PI, false); 
13      //变换原点
14      context.translate(100, 100); 
15      //旋转表针
16      context.rotate(1); 
17      //绘制分针 
18      context.moveTo(0,0);
19      context.lineTo(0, -85); 
20      //绘制时针
21      context.moveTo(0, 0);
22      context.lineTo(-65, 0); 
23      //描边路径
24      context.stroke();
25    } 
26 }

效果图:

  无论是刚才执行的变换,还是fillStyle、strokeStyle 等属性,都会在当前上下文中一直有效, 除非再对上下文进行什么修改,通过save()、 restore()方法可保存和恢复上下文,这两个方法通过一个栈来实现。

6、绘制图像 

   如果想把一幅图像绘制到画布上,可以使用drawImage()方法,结合其他方法,可以对图像进行各种基本操作,操作的结果可以通过 toDataURL()方法获得,有一个例外,即图像不能来自其他域。如果图像来自其他域,调用 toDataURL()会抛出一个错误。

7、阴影

 2D上下文会根据以下几个属性的值,自动为形状或路径绘制出阴影。

   shadowColor:用CSS颜色格式表示的阴影颜色,默认为黑色;
   shadowOffsetX:形状或路径x轴方向的阴影偏移量,默认为0。
   shadowOffsetY:形状或路径y轴方向的阴影偏移量,默认为0。
   shadowBlur:模糊的像素数,默认0,即不模糊。

8、渐变

   渐变由 CanvasGradient 实例表示,很容易通过 2D上下文来创建和修改。要创建一个新的线性渐变,可以调用createLinearGradient()方法; addColorStop()方法用来指定渐变的色标。

   如下是一个例子:

 1 window.onload = function(){
 2    //这个函数基于起点的x和y坐标以及宽度和高度来创建渐变对象,使得在fillRect()中可用相同的值,便于控制。 
 3    function createRectLinearGradient(context, x, y, width, height){
 4       return context.createLinearGradient(x, y, x+width, y+height);
 5    }
 6    var drawing = document.getElementById("drawing"); 
 7    if(drawing.getContext){ 
 8        var context = drawing.getContext("2d"); 
 9        //绘制红色矩形
10        context.fillStyle = "#ff0000";
11        context.fillRect(10, 10, 50, 50); 
12        var gradient = createRectLinearGradient(context, 30, 30, 50, 50);  
13        gradient.addColorStop(0, "white");
14        gradient.addColorStop(1, "black"); 
15        //绘制渐变矩形
16        context.fillStyle = gradient;
17        context.fillRect(30, 30, 50, 50); 
18    }
19 }

效果图:

如果要创建径向渐变(或放射渐变),可以使用 createRadialGradient()方法。

代码:

window.onload = function(){
   var drawing = document.getElementById("drawing"); 
   if(drawing.getContext){ 
       var context = drawing.getContext("2d"); 
       var gradient = context.createRadialGradient(55, 55, 10, 55, 55, 30); 
       gradient.addColorStop(0, "white"); gradient.addColorStop(1, "black"); 
       //绘制红色矩形
       context.fillStyle = "#ff0000";
       context.fillRect(10, 10, 50, 50); 
       //绘制渐变矩形
       context.fillStyle = gradient;
       context.fillRect(30, 30, 50, 50);  
   }
}

效果图:

9、模式

模式其实就是重复的图像,可以用来填充或描边图形。要创建一个新模式,可以调用 createPattern()方法并传入两个参数:一个 HTML<img>元素和一个表示如何重复图像的字符串。

10、使用图像数据

    2D上下文的一个明显的长处就是,可以通过 getImageData()取得原始图像数据。这个方法接收 4个参数:要取得其数据的画面区域的x和y坐标以及该区域的像素宽度和高度。

    例如,要取得左上角坐标为(10,5)、大小为 50×50像素的区域的图像数据,可以使用以下代码:
        var imageData = context.getImageData(10, 5, 50, 50); 

    这里返回的对象是ImageData的实例。每个ImageData对象都有三个属性:width、height和data。其中data属性是一个数组,保存着图像中每一个像素的数据。在data数组中,每一个像素用4个元素来保存,分别表示红、绿、蓝和透明度值。因此,第一个像素的数据就保存在数组的第0到第3个元素中可以据此直接操作原始图像数据。

11、合成

    还有两个会应用到 2D上下文中所有绘制操作的属性:globalAlpha 和 globalComposition-Operation。

   其中,globalAlpha 是一个介于 0和 1之间的值(包括0和1),用于指定所有绘制的透明度。默认值为0。如果所有后续操作都要基于相同的透明度,就可以先把 globalAlpha设置为适当值,然后绘制,后再把它设置回默认值0。

  globalCompositionOperation属性则表示后绘制的图形怎样与先绘制的图形结合。这个属性的值是字符串。

二、WebGL

 WebGL上下文是一种3D上下文。WebGL是从OpenGL ES 2.0移植到浏览器中的,OpenGL ES 2.0是游戏开发人员在创建计算机图形图像时经常使用的一种语言。

 WebGL支持比 2D上下文更丰富 和更强大的图形图像处理能力,比如:

         a、用GLSL编写的顶点和片段着色器;
         b、支持类型化数组,即能够将数组中的数据限定为某种特定的数值类型;
         c、创建和操作纹理;        

 从稳妥的角度考虑,在使用 WebGL之前,最好检测其是否得到了支持。WebGL 还是一个正在制定和发展中的规范。不管是函数名、函数签名,还是数据类型,都有可能改变。可以说,WebGL目前只适合实验性地学习,不适合真正开发和应用。 

第十六章、HTML5脚本编程

    HTML5除了定义了新的标记规则,还定义了一些 JavaScript API。这些 API是为了让开发人员创建出更好的、能够与桌面应用媲美的用户界面而设计的。

一、跨文档消息传递

    跨文档消息传送,有时候简称为XDM,指的是在来自不同域的页面间传递消息。

   XDM的核心是postMessage()方法。在HTML5规范中,除了XDM部分之外的其他部分也会提到这个方法名,但都是为了同一个目的:向另一个地方传递数据。对于XDM而言,“另一个地方”指的是包含在当前页面中的<iframe>元素,或者由当前页面弹出的窗口。 

   接收到 XDM消息时,会触发 window 对象的message事件。这个事件是以异步形式触发的。

二、原生拖放

   原生拖放功能让我们可以方便地指定某个元素可拖动,并在操作系统要放置时做出响应。还可以创建自定义的可拖动元素及放置目标。

   1、 与拖放相关的事件有:dragstart、drag、dragend、dragenter、dragover、dragleave(或drop);

   2、 dataTransfer 对象,它是事件对象的一个属性,用于从被拖动元素向放置目标传递字符串格式的数据。dataTransfer对象有两个主要方法:getData()和 setData()。

      如:

             //设置和接收文本数据
              event.dataTransfer.setData("text", "some text");
              var text = event.dataTransfer.getData("text");
            //设置和接收 URL
              event.dataTransfer.setData("URL", "http://www.wrox.com/"); 
              var url = event.dataTransfer.getData("URL");

    3、利用 dataTransfer 对象,还能通过它来确定被拖动的元素以及作为放置目标的元素能够接收什么操作。为此,需要访问dataTransfer对象的两个属性:dropEffect和 effectAllowed。

   4、HTML5还为所有 HTML元素规定了一个 draggable属性,表示元素是否可以拖动。

三、媒体元素 

    HTML5新增了<audio>和<video>这两个与媒体相关的标签,让开发人员不必依赖任何插件就能在网页中嵌入跨浏览器的音频和视频内容。 

    用法如下:

<!-- 嵌入视频 --> 
<video src="conference.mpg" id="myVideo">Video player not available.</video> 
<!-- 嵌入音频 --> 
<audio src="song.mp3" id="myAudio">Audio player not available.</audio> 

   使用这两个元素时,至少要在标签中包含src属性,指向要加载的媒体文件。还可以设置width和height属性以指定视频播放器的大小,而为poster属性指定图像的URI可以在加载视频内容期间显示一幅图像。另外,如果标签中有controls属性,则意味着浏览器应该显示UI控件,以便用户直接操作媒体。

   因为并非所有浏览器都支持所有媒体格式,所以可以指定多个不同的媒体来源。为此,不用在标签中指定src 属性,而是要像下面这样使用一或多个<source>元素。 

<!-- 嵌入视频 -->
<video id="myVideo">
    <source src="conference.webm" type="video/webm; codecs='vp8, vorbis'">
    <source src="conference.ogv" type="video/ogg; codecs='theora, vorbis'">
    <source src="conference.mpg">
    Video player not available.
</video>
<!-- 嵌入音频 -->
<audio id="myAudio">
    <source src="song.ogg" type="audio/ogg">
    <source src="song.mp3" type="audio/mpeg">
    Audio player not available.
</audio>

  这两个媒体元素有许多属性,还可以触发很多的事件。使用<audio>和<video>元素的 play()和 pause()方法,可以手工控制媒体文件的播放。组合使用属性、事件和这两个方法,很容易创建一个自定义的媒体播放器,如下面的例子所示。

  <div class="mediaplayer">
    <div class="video">
       <video id="player" src="movie.mov" poster="mymovie.jpg"             width="300" height="200">
         Video player not available.
       </video>
    </div>
    <div class="controls">
       <input type="button" value="Play" id="video-btn">
       <span id="curtime">0</span>/<span id="duration">0</span>
    </div>
  </div>
   //取得元素的引用
   var player = document.getElementById("player"),
       btn = document.getElementById("video-btn"),
       curtime = document.getElementById("curtime"),
       duration = document.getElementById("duration");
   //更新播放时间
   duration.innerHTML = player.duration;
   //为按钮添加事件处理程序
   EventUtil.addHandler(btn, "click", function(event){
    if (player.paused){
        player.play();
        btn.value = "Pause";
    } else {
        player.pause();
        btn.value = "Play";
    }
   });
   //定时更新当前时间
   setInterval(function(){
    curtime.innerHTML = player.currentTime;
   }, 250);

     以上JavaScript代码给按钮添加了一个事件处理程序,单击它能让视频在暂停时播放,在播放时暂停。通过<video>元素的load事件处理程序,设置了加载完视频后显示播放时间。最后,设置了一个 计时器,以更新当前显示的时间。

 四、历史状态管理

     历史状态管理让我们不必卸载当前页面即可修改浏览器的历史状态栈。有了这种机制,用户就可以通过“后退”和“前进”按钮在页面状态间切换,而这些状态完全由JavaScript进行控制。要管理历史状态首选使用hashchange事件。HTML5通过更新history对象为管理历史状态提供了方便。 

第十七章 错误处理与调试 

 一、错误处理

   1、try-catch语句 

      常见用法:

1 try {// 可能会导致错误的代码
2     window.someNonexistentFunction();
3 } catch (error){ // 在错误发生时怎么处理
4     alert(error.message);
5 }

 2、finally 子句

 finally在try-catch语句中是可选的,但finally子句一经使用,其代码无论如何都会执行。注意,只要代码中包含finally子句,那么无论 try还是catch语句块中的return语句都将被忽略。因此,在使用finally子句之前,一定要非常清楚你想让代码怎么样。 

1 function testFinally(){
2     try {
3         return 2;
4     } catch (error){
5         return 1;
6     } finally {
7         return 0;
8     }
9 }

上述代码,执行后函数会返回0。

3、错误类型 

ECMA-262 定义了下列7种错误类型:Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError。

Error是基类型,其他错误类型都继承自该类型。

4、抛出错误

  与try-catch语句相配的还有一个throw操作符,用于随时抛出自定义错误。抛出错误时,必须 要给throw操作符指定一个值,这个值是什么类型,没有要求。

  在遇到throw操作符时,代码会立即停止执行。仅当有try-catch语句捕获到被抛出的值时,代码才会继续执行。

      抛出错误示范:throw new Error("Something bad happened."); 

  还可以创建抛出自定义的错误,下面是利用原型链继承Error来创建自定义错误类型:

1 //创建自定义错误类型
2 function CustomError(message){
3     this.name = "CustomError";
4     this.message = message;
5 }
6 CustomError.prototype = new Error();
7 throw new CustomError("My message");

 抛出错误的时机:应该在出现某种特定的已知错误条件,导致函数无法正常执行时抛出错误,如:

 1 function process(values){
 2     if (!(values instanceof Array)){
 3         throw new Error("process(): Argument must be an array.");
 4     }
 5     values.sort();
 6     for (var i=0, len=values.length; i < len; i++){
 7         if (values[i] > 100){
 8             return values[i];
 9         }
10     }
11     return -1;
12 }

5、错误(error)事件

任何没有通过try-catch处理的错误都会触发window对象的error事件。要指定onerror事件处理程序,必须使用如下所示的DOM0级技术,它没有遵循“DOM2级事件”的标准格式。 

window.onerror = function(message, url, line){
    alert(message);
};

 图像也支持 error 事件。只要图像的src特性中的URL不能返回可以被识别的图像格式,就会触发error事件。此时的error事件遵循 DOM格式,会返回一个以图像为目标的event对象,下面是 一个例子。

1 var image = new Image();
2 EventUtil.addHandler(image, "load", function(event){
3     alert("Image loaded!");
4 });
5 EventUtil.addHandler(image, "error", function(event){
6     alert("Image not loaded!");
7 });
8 image.src = "smilex.gif"; //指定不存在的文件

在这个例子中,当加载图像失败时就会显示一个警告框。需要注意的是,发生error事件时,图像下载过程已经结束,也就是说不能再重新下载了。 

6、常见的导致错误的类型:

      a、类型转换错误:类型转换错误发生在使用某个操作符,或者使用其他可能会自动转换值的数据类型的语言结构时。在使用相等            (==)和不相等(!=)操作符,或者在 if、 for 及 while 等流控制语句中使用非布尔值时,最常发生类型转换错误。
      b、数据类型错误:在将预料之外的值传递给函数的情况下,最容易发生数据类型错误。
      c、通信错误:第一种通信错误与格式不正确的 URL 或发送的数据有关。最常见的问题是在将数据发送给服务器之前,没有使用                encodeURIComponent()对数据进行编码。 另外,在服务器响应的数据不正确时,也会发生通信错误。

7、非致命错误:不影响用户的主要任务;只影响页面的一部分;可以恢复;重复相同操作可以消除错误。
      致命错误: 应用程序根本无法继续运行; 错误明显影响到了用户的主要操作; 会导致其他连带错误。 

8、开发 Web 应用程序过程中的一种常见的做法,就是集中保存错误日志,以便查找重要错误的原因。推荐把JavaScript错误回写到服务器。

二、调试技术 

 1、将消息记录到控制台 

    对 IE8、 Firefox、 Chrome 和 Safari 来说,可以通过 console 对象向 JavaScript 控制台中写入消息,这个对象具有下列方法。
        a、error(message):将错误消息记录到控制台
        b、info(message):将信息性消息记录到控制台
        c、log(message):将一般消息记录到控制台
        d、warn(message):将警告消息记录到控制台

 如:

function sum(num1, num2){
    console.log("Entering sum(), arguments are " + num1 + "," + num2);
    console.log("Before calculation");
    var result = num1 + num2;
    console.log("After calculation");
    console.log("Exiting sum()");
    return result;
}

   还有一种方案是使用 LiveConnect,也就是在 JavaScript 中运行Java代码。 Firefox、 Safari 和 Opera都支持LiveConnect,因此可以操作Java 控制台。

1 function sum(num1, num2){
2     java.lang.System.out.println("Entering sum(), arguments are " + num1 + "," + num2);
3     java.lang.System.out.println("Before calculation");
4     var result = num1 + num2;
5     java.lang.System.out.println("After calculation");
6     java.lang.System.out.println("Exiting sum()");
7     return result;
8 }

2、将消息记录到当前页面 

  另一种输出调试消息的方式,就是在页面中开辟一小块区域,用以显示消息。这个区域通常是一个元素,而该元素可以总是出现在页面中,但仅用于调试目的;也可以是一个根据需要动态创建的元素。 例如,可以将 log()函数修改为如下所示:

 1 function log(message){
 2     var console = document.getElementById("debuginfo");
 3     if (console === null){
 4         console = document.createElement("div");
 5         console.id = "debuginfo";
 6         console.style.background = "#dedede";
 7         console.style.border = "1px solid silver";
 8         console.style.padding = "5px";
 9         console.style.width = "400px";
10         console.style.position = "absolute";
11         console.style.right = "0px";
12         console.style.top = "0px";
13         document.body.appendChild(console);
14     }
15     console.innerHTML += "<p>" + message + "</p>";
16 }

三、常见的 IE错误 

  常见IE错误有:操作终止、无效字符、未找到成员、未知运行时错误、语法错误、系统无法找到指定资源等 

猜你喜欢

转载自www.cnblogs.com/xiaoxb17/p/11919446.html