JavaScript高级程序设计:学习笔记9--使用Canvas绘图和HTML5脚本编程

1. 使用Canvas绘图

1. 基本用法

    要使用<canvas>元素,必须先设置其width和height属性,指定可以绘图的区域大小.出现在开始和结束标签中的内容是后备信息,如果浏览器不支持就显示这些信息.

    要在这块画布上绘图,需要取得绘图上下文,则需要调用getContext()方法并传入上下文的名字,例如传入"2d".

    我们可以使用toDataURL()方法导出在<canvas>元素上绘制的图像.一个具体实例如下:

<!DOCTYPE html>
<html>
 <head>
    <title>Canvas Fill Rect Example</title>
 </head>
 <body>
    <canvas id="drawing" width="200" height="200">Your browser doesn't support the canvas tag.</canvas>
    <input type="button" value="Export" id="export-btn" >
    <script type="text/javascript">
        window.onload = function(){
            var drawing = document.getElementById("drawing"),
                btn     = document.getElementById("export-btn");
            
            //make sure <canvas> is completely supported
            if (drawing.getContext){
            
                var context = drawing.getContext("2d");
            
                //draw a red rectangle
                context.fillStyle = "#ff0000";
                context.fillRect(10, 10, 50, 50);
            
                //draw a blue rectangle that's semi-transparent
                context.fillStyle = "rgba(0,0,255,0.5)";
                context.fillRect(30, 30, 50, 50);
            }                
            
            btn.onclick = function(){
                //get data URI of the image
                var imgURI = drawing.toDataURL();
                
                //display the image
                var image = document.createElement("img");
                image.src = imgURI;
                document.body.appendChild(image);    

            };
        };

    </script>
    </body>
</html>
浏览器显示如下:

JavaScript高级程序设计:学习笔记9--使用Canvas绘图和HTML5脚本编程_第1张图片

2. 2D上下文

1. 填充和描边

    填充,就是用指定的样式填充图形;描边,就是只在图形的边缘画线,分别涉及到两个属性:fillStyle和strokeStyle:

 if (drawing.getContext){
     var context = drawing.getContext("2d");
       
     context.strokeStyle = "red";
     context.fillStyle = "#0000ff";
}
备注:这里是预先设定格式,然后绘制图形(而并非将这个绘制区域的填充改为#0000ff,描边改为red)参考下一节:绘制矩形.

2. 绘制矩形

    矩形是唯一一种可以在2D上下文中绘制的形状.与矩形有关的方法包括fillRect(),strokeRect()和clearRect().这三个方法都能接收4个参数:矩形的x坐标,矩形的y坐标,矩形的宽度和矩形的高度.这些参数的单位都是像素.

2.1 fllRect()方法在画布上绘制的矩形会填充指定的颜色,而填充的颜色通过fillStyle属性指定:

        window.onload = function(){
            var drawing = document.getElementById("drawing");
            
            //make sure <canvas> is completely supported
            if (drawing.getContext){
                var context = drawing.getContext("2d");
       
       			//绘制红色矩形
                context.fillStyle = "#ff0000";
                context.fillRect(10, 10, 50, 50);
                
                //绘制半透明的蓝色矩形
                context.fillStyle = "rgba(0, 0, 255, 0.5)";
                context.fillRect(30, 30, 50, 50);
            }  
        };
浏览器显示如下:

JavaScript高级程序设计:学习笔记9--使用Canvas绘图和HTML5脚本编程_第2张图片

2.2 strokeRect()方法在画布上绘制的矩形会使用指定的颜色描边.描边的颜色通过strokeStyle属性指定:

            var drawing = document.getElementById("drawing");
            
            //make sure <canvas> is completely supported
            if (drawing.getContext){
            
                var context = drawing.getContext("2d");
       
       			//绘制红色描边矩形
                context.strokeStyle = "#ff0000";
                context.strokeRect(10, 10, 50, 50);
                
                //绘制半透明的蓝色描边矩形
                context.strokeStyle = "rgba(0, 0, 255, 0.5)";
                context.strokeRect(30, 30, 50, 50);
            }
浏览器显示如下:

JavaScript高级程序设计:学习笔记9--使用Canvas绘图和HTML5脚本编程_第3张图片

2.3 clearRect()方法用于清除画布上的矩形区域:

var drawing = document.getElementById("drawing");
            
            //make sure <canvas> is completely supported
            if (drawing.getContext){
            
                var context = drawing.getContext("2d");
       
       			//绘制红色矩形
                context.fillStyle = "#ff0000";
                context.fillRect(10, 10, 50, 50);
                
                //绘制半透明的蓝色矩形
                context.fillStyle = "rgba(0, 0, 255, 0.5)";
                context.fillRect(30, 30, 50, 50);
                
                //在两个矩形重叠的地方清除一个小矩形
                context.clearRect(40, 40, 10, 10);
               }
浏览器显示如下: JavaScript高级程序设计:学习笔记9--使用Canvas绘图和HTML5脚本编程_第4张图片

3. 绘制路径

    要绘制路径,首先必须调用beginPath()方法,表示要开始绘制新路径.然后,再通过调用下列方法来实际的绘制路径

1. arc(x, y, radius, startAngle, endAngle, counterclockwise):以(x,y)为圆心绘制一条弧线,弧线的半径为radius,起始和结束角度(用弧度表示)分别为startAngle和endAngle.最后一个参数表示startAngle和endAngle是否按逆时针方向计算,值为false表示按顺时针方向计算.
2. arcTo(x1, y1, x2, y2, radius):从上一点开始绘制一条弧线,到(x2, y2)为止,并且以给定的半径radius穿过(x1, y1)
3. bezierCurveTo(c1x, c1y, c2x, c2y, x, y):从上一点开始绘制一条曲线,到(x,y)为止,并且以(c1x, c1y)和(c2x, c2y)为控制点.
4. lineTo(x, y):从上一点开始绘制一条直线,到(x, y)为止.
5. moveTo(x, y):将绘图游标移动到(x, y),不画线.
6. quadraticCurveTo(cx, cy, x, y):从上一点开始绘制一条二次曲线,到(x, y)为止,并且以(cx, cy)作为控制点.
7. rect(x, y, width, height):从点(x, y)开始绘制一个矩形,宽度和高度分别由width和height指定.这个方法绘制的是矩形路径,而不是strokeRect()和fillRect()所绘制的独立的形状.

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

            var drawing = document.getElementById("drawing");
            
            //make sure <canvas> is completely supported
            if (drawing.getContext){
            	var context = drawing.getContext("2d");
            	
            	//开始路径  
	            context.beginPath();
	            
	            //绘制外圆
	            context.arc(100, 100, 99, 0, 2 * Math.PI, false);
	            
	            //绘制内圆
	            context.moveTo(194, 100);	//如果没有这句话,则图形将从(200,0)开始绘制内圆
	            context.arc(100, 100, 94, 0, 2 * Math.PI, false);
	            
	            //绘制分针
	            context.moveTo(100, 100);
	            context.lineTo(100, 15);
	            
	            //绘制时针
	            context.moveTo(100, 100);
	            context.lineTo(35, 100);
	            
	            //描边路径--显示所绘制的钟表
	            context.stroke(); 
              }
浏览器显示如下:


JavaScript高级程序设计:学习笔记9--使用Canvas绘图和HTML5脚本编程_第5张图片

4. 绘制文本

    绘制文本通常有两个方法:fillText()和strokeText().这两个方法都可以接收4个参数:要绘制的文本字符串,x坐标,y坐标和可选的最大像素值.而且这三个方法都以下列3个属性为基础:

1. font:表示文本样式,大小及字体,用CSS中指定字体的格式来指定.
2. textAlign:表示文本对其方式.可能的值有"start","end","left","right"和"center".不推荐使用"left"和"right".
3. textBaseline:表示文本的基线.可能的值有"top","hanging","middle","alphabetic","ideographic"和"bottom".值为top,y坐标表示文本顶端,值为"bottom",y坐标表示文本底端,值为hanging,alphabetic和ideographic,则y坐标分别指向字体的特定基线坐标.

    fillText()方法使用fillStyle属性绘制文本,而strokeText()方法是用strokeStyle属性为文本描边.

实例如下:

	            context.font = "bold 14px Arial";
	            context.textAlign = "center";
	            context.textBaseline = "middle";
	            context.fillText("12", 100, 20);
浏览器显示如下:


JavaScript高级程序设计:学习笔记9--使用Canvas绘图和HTML5脚本编程_第6张图片

5. 变换

1. rotate(angle):围绕远点旋转图像angle弧度.
2. scale(scaleX, scaleY):缩放图像,在X方向乘以scaleX,在y方向乘以scaleY.scaleX和scaleY的默认值是1.0
3. translate(x, y):将坐标原定移动到(x, y).执行这个变换之后,坐标(0,0)会变成之前由(x,y)表示的点.
4. transform(m1_1, m1_2, m2_1, m2_2, dx, dy):直接修改变换矩阵,方法是乘以如下矩阵:
m1_1 m1_2 dx
m2_1 m2_2 dy
0      0    1
5. setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy):将变换矩阵重置为默认状态,然后再调用transform

实例如下:

            var drawing = document.getElementById("drawing");
            
            if (drawing.getContext) {
            	var context = drawing.getContext("2d");
            	
            	//开始路径  
	            context.beginPath();
	            
	            //绘制外圆
	            context.arc(100, 100, 99, 0, 2 * Math.PI, false);
	            
	            //绘制内圆
	            context.moveTo(194, 100);	//如果没有这句话,则图形将从(200,0)开始绘制内圆
	            context.arc(100, 100, 94, 0, 2 * Math.PI, false);
	            
	            //变换原点
	            context.translate(100, 100);
	            
	            //旋转表针
	            context.rotate(1);
	            
	            //绘制分针
	            context.moveTo(0, 0);
	            context.lineTo(0, -85);
	            
	            //绘制时针
	            context.moveTo(0, 0);
	            context.lineTo(-65, 0);
	            
	           	context.stroke();
            }
浏览器显示如下:


JavaScript高级程序设计:学习笔记9--使用Canvas绘图和HTML5脚本编程_第7张图片

    而我们可以通过save()在堆栈中保存设置,而通过restore()方法恢复上一级状态.我们可以连续使用save()和restore()方法:

            	var context = drawing.getContext("2d");
            	
            	context.fillStyle = "#ff0000";
            	context.save();
            	
            	context.fillStyle = "#00ff00";
            	context.translate(100, 100);
            	context.save();
            	
            	context.fillStyle = "#0000ff";
            	context.fillRect(0, 0, 100, 200);	//从点(100, 100)开始绘制蓝色矩形
            	
            	context.restore();	//注意:这里坐标位置的变换仍然起作用
            	context.fillRect(10, 10, 100, 200);	//从点(110, 110)开始绘制绿色矩形
            	
            	context.restore();
            	context.fillRect(0, 0, 100, 200);	//从点(0, 0)开始绘制红色矩形
浏览器显示如下:


JavaScript高级程序设计:学习笔记9--使用Canvas绘图和HTML5脚本编程_第8张图片

6. 绘制图像

    使用drawImage()方法来绘制图像.有三种不同的参数组合:
1. 传入一个HTML<img>元素,以及绘制该图像的起点的x和y坐标.
2. 再多传两个参数,分别表示目标宽度和目标高度(进行缩放)
3. 再多传4个参数,表示目标图像的x,y坐标和目标图像的宽度和高度(并没有进行缩放):

实例如下:

        window.onload = function(){
            var drawing = document.getElementById("drawing");
            
            if (drawing.getContext) {
            	var context = drawing.getContext("2d");
                var image = document.getElementById("smiley");
                
                //draw regular size
                context.drawImage(image, 10, 10);
                
                //draw smaller
                context.drawImage(image, 50, 10, 20, 30);

                //draw just part of the image
                context.drawImage(image, 0, 10, 50, 50, 0, 100, 40, 60);
            }
        };
浏览器显示如下:


JavaScript高级程序设计:学习笔记9--使用Canvas绘图和HTML5脚本编程_第9张图片

7. 阴影

1. shadowColor:用CSS颜色格式表示的阴影颜色,默认为黑色
2. shadowOffsetX:形状或路径x轴方向的阴影偏移量,默认为0
3. shadowOffsetY:形状或路径y轴方向的阴影偏移量,默认为0
4. shadowBlur:模糊的像素数,默认0,即不模糊
实例如下:

            	var context = drawing.getContext("2d");
            	
            	//设置阴影
            	context.shadowOffsetX = 5;
            	context.shadowOffsetY = 5;
            	context.shadowBlur = 4;
            	context.shadowColor = "rgba(0, 0, 0, 0.5)";
            	
            	//绘制红色矩形
            	context.fillStyle = "#ff0000";
            	context.fillRect(10, 10, 50, 50);
            	
            	//绘制蓝色矩形
            	context.fillStyle = "rgba(0, 0, 255, 1)";
            	context.fillRect(30, 30, 50, 50);
浏览器显示如下:

JavaScript高级程序设计:学习笔记9--使用Canvas绘图和HTML5脚本编程_第10张图片

8. 渐变

    渐变由CanvasGradient实例表示,调用createLinearGradient()方法,此方法接收4个参数:起点的x坐标,起点的y坐标,终点的x坐标,终点的y坐标.调用这个方法后,它就会创建一个指定大小的渐变,并返回CanvasGradient对象实例.
    创建了渐变对象后,下一步就是使用addColorStop()方法来指定色标.接收两个参数:色标位置和CSS颜色值.色标位置是一个0(开始的颜色)到1(结束的颜色)之间的数字.
实例如下:

				var context = drawing.getContext("2d");
            	
            	var gradient = context.createLinearGradient(30, 30, 70, 70);
            	gradient.addColorStop(0, "white");
            	gradient.addColorStop(1, "red");
            	
            	//绘制红色矩形
            	context.fillStyle = "#00ff00";
            	context.fillRect(10, 10, 50, 50);
            	
            	//绘制渐变矩形
            	context.fillStyle = gradient;
            	context.fillRect(30, 30, 50, 50);
浏览器显示如下:

JavaScript高级程序设计:学习笔记9--使用Canvas绘图和HTML5脚本编程_第11张图片

9. 模式

    模式就是重复的图像,可以用来填充或描边图形.要创建一个新模式,可以调用createPattern()方法并传入两个参数:一个HTML<img>元素和一个表示如何重复图像的字符串.其中,第二个参数的值与CSS的background-repeat属性值相同,包括"repeat","repeat-x","repeat-y","no-repeat":
实例如下:

		var context = drawing.getContext("2d"),
                    image = document.images[0],
                    pattern = context.createPattern(image, "repeat");

                //draw a rectangle
                context.fillStyle = pattern;
                context.fillRect(10, 10, 150, 150);
浏览器显示如下:

JavaScript高级程序设计:学习笔记9--使用Canvas绘图和HTML5脚本编程_第12张图片

10. 使用图像数据

    通过getImageData()取得原始图像数据.这个方法接收4个参数:要取得其数据的画面区域的x和y坐标以及该区域的像素宽度和高度:

var imageData = context.getImageData(10, 5, 50, 50);
    这里返回的对象是ImageData的实例,每个ImageData对象有三个属性:width,height和data.其中data是一个数组,保存着图像中每一个像素的数据.在data数组中,每一个像素用4个元素来保存,分别表示红,绿,蓝和透明度值.
    以下代码创建一个简单的灰阶过滤器:
window.onload = function(){
            var drawing = document.getElementById("drawing");
            
            //make sure <canvas> is completely supported
            if (drawing.getContext){
            
                var context = drawing.getContext("2d"),
                    image = document.images[0],
                    imageData, data,
                    i, len, average,
                    red, green, blue, alpha;
                
                //draw regular size
                context.drawImage(image, 0, 0);    
                
                //get the image data
                imageData = context.getImageData(0, 0, image.width, image.height);
                data = imageData.data;

                for (i=0, len=data.length; i < len; i+=4){
                
                    red = data[i];
                    green = data[i+1];
                    blue = data[i+2];
                    alpha = data[i+3];
                    
                    //get the average of rgb
                    average = Math.floor((red + green + blue) / 3);
                    
                    //set the colors, leave alpha alone
                    data[i] = average;
                    data[i+1] = average;
                    data[i+2] = average;
                    
                }
                
                //assign back to image data and display
                imageData.data = data;                
                context.putImageData(imageData, 0, 0);
            }                
        };
浏览器显示如下:

JavaScript高级程序设计:学习笔记9--使用Canvas绘图和HTML5脚本编程_第13张图片

2. HTML5脚本编程

1. 跨文档消息传递

    跨文档消息传递(也简称为XDM),指的是在来自不同域的页面间传递消息.
    XDM的核心是postMessage()方法,作用是向另一个地方传递数据.另一个地方指的是包含在当前页面中的<iframe>元素,或者由当前页面弹出的窗口.
    postMessage方法接收两个参数:一条消息和一个表示消息接收方来自哪个域的字符串.第二个参数对保障安全通信非常重要,可以防止浏览器把消息发送到不安全的地方.


//注意:所有支持XDM的浏览器也支持iframe的contentWindow属性
var iframeWindow = document.getElementById("myframe").contentWindow;
iframeWindow.postMessage("a secret", "http://www.wrox.com");
    接收到XDM消息时,会触发window对象的message事件.这个事件是以异步形式触发的,所以会存在延迟.触发message事件后,传递给onmessage处理程序的事件对象包含以下三方面的重要信息:


1. data:作为postMessage()第一个参数传入的字符串数据.
2. origin:发送消息的文档所在的域.
3. source:发送消息的文档的window对象的代理.如果来自同一个域,就是window.

    接收到消息后验证发送窗口的来源是至关重要的:


EventUtil.addHandler(window, "message", function(event) {
	//确保发送消息的域是已知的域
	if (event.origin == "http://www.wrox.com") {
		//处理接收到的数据
		processMessage(event.data);
		
		//可选:向来源窗口发送回执
		event.source.postMessage("received!", "http://p2p.wrox.com");
	}
});


2. 原生拖放

1. 拖放事件

    拖动某元素时,会依次触发以下事件:

1. dragstart:按下鼠标键并开始移动鼠标时触发
2. drag:拖动期间触发
3. dragend:停止拖动时候触发

    当某个元素被拖动到一个有效的放置目标上时,下列事件会依次发生:

1. dragenter:元素被拖动到放置目标上
2. dragover:在放置目标上移动
3. dragleave或drop:拖出了放置目标触发dragleave,放到了放置目标触发drop.

2. 自定义放置目标

    对于无效的放置目标,我们通过取消dragenter和dragover的默认行为,来使目标变为有效:


var droptarget = document.getElementById("droptarget");

EventUtil.addHandler(droptarget, "dragover", function(event){
	EventUtil.preventDefault(event);
});

EventUtil.addHandler(droptarget, "dragenter", function(event){
	EventUtil.preventDefault(event);
});

//firefox3.5+中,放置时间的默认行为是打开其URL,所以也得取消drop事件的默认行为
EventUtil.addHandler(droptarget, "drop", function(event){
	EventUtil.preventDefault(event);
});


3. dataTransfer对象

    dataTransfer是事件对象的属性,所以只能在拖放事件的事件处理程序中访问dataTransfer对象.它有两个主要方法:getData()和setData():getData可以取得由setData保存的值,而setData方法的第一个参数,也是getData()方法唯一的一个参数,是一个字符串,表示保存的数据类型,取值为"text"或"URL":


//设置和接收文本数据
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");
    保存在dataTransfer对象中的数据只能在drop事件处理程序中读取.如果在ondrop处理程序中没有读到数据,那就是dataTransfer对象已经被销毁,数据也丢失了.
    在拖动文本框中的文本时,浏览器会调用setData()方法,将拖动的文本以"text"格式保存在dataTransfer对象中.类似的,在拖放链接或图像时,会调用setData()方法并保存URL.然后,在这些元素被拖放到放置目标时,就可以通过getData()读到这些数据.


实例如下:


<!DOCTYPE html>
<html>
<head>
    <title>Data Transfer Example</title>
    <script type="text/javascript" src="EventUtil.js"></script>
</head>
<body>
    <p>Try dragging the link over to the red square. This won't work correctly in Opera.</p>
    <a href="http://www.wrox.com">Wrox homepage</a>
    <div style="width: 100px; height: 100px; float: middle; background: red" id="droptarget"></div>
    <div id="output"></div>
    <script type="text/javascript">
        var droptarget = document.getElementById("droptarget");
        
        function handleEvent(event){
            document.getElementById("output").innerHTML += event.type + "<br>";
            switch(event.type){
                case "drop":
                case "dragdrop":
                    droptarget.innerHTML = event.dataTransfer.getData("url") || event.dataTransfer.getData("text/uri-list");
                    /* falls through */

                case "dropenter":
                case "dragover":
                    EventUtil.preventDefault(event);
                    break;
            }

        }

        EventUtil.addHandler(droptarget, "dragenter", handleEvent);
        EventUtil.addHandler(droptarget, "dragover", handleEvent);
        EventUtil.addHandler(droptarget, "dragleave", handleEvent);
        EventUtil.addHandler(droptarget, "drop", handleEvent);

    </script>
</body>
</html>
浏览器显示如下:


JavaScript高级程序设计:学习笔记9--使用Canvas绘图和HTML5脚本编程_第14张图片

4. dropEffect与effectAllowed

    通过dataTransfer对象,可以确定被拖动的元素以及作为放置目标的元素能够接收什么操作,额外的两个属性为:dropEffect和effectAllowed:
1. dropEffect属性可以知道被拖动的元素能够执行哪些放置行为:
"none":不能把拖放元素放在这里,这是除文本框之外所哟元素的默认值.
"move":应该把拖放的元素移动到放置目标.
"copy":应该把拖放的元素复制到放置目标.
"link":表示放置目标会打开拖动的元素.
    要使用dropEffect属性,必须在ondragenter事件处理程序中针对放置目标来设置它.
2. effectAllowed属性表示允许拖动元素的哪种dropEffect:
"uninitialized":没有给被拖动的元素设置任何放置行为
"none":被拖动元素不能有任何行为
"copy":只允许值为"copy"的dropEffect
"link":只允许值为"link"的dropEffect
"move":只允许值为"move"的dropEffect
"copyLink":只允许值为"copy"和"link"的dropEffect
"copyMove":只允许值为"copy"和"move"的dropEffect
"linkMove":只允许值为"link"和"move"的dropEffect
"all":允许任意dropEffect
    必须在ondragstart事件处理程序中设置effectAllowed属性.

5. 可拖动

    HTML5为所有HTML元素规定了一个draggable属性,为true表示可以拖动,为false表示不能拖动.




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