HTML5系列五(Canvas详述)

写在前面

闲来无事的时候会来一场一个人说走就走的旅行或者宅家里系统性的看些技术方面的书,最近在看《html5与css3权威指南》,这本书挺适合初学前端的人,虽然对于我来说只是温习相关的知识,但好歹来说开卷有益,只要是一本好书,即使知识很浅也值得一看。

(我会在相关代码注释中揭示canvas对象相关方法各参数的含义)

写的不好的地方还望大家见谅

canvas概述

canvas标签非常的简洁,常用的就width和height两个属性

大多数 canvas 绘图 API 都没有定义在 <canvas> 元素本身上,而是定义在通过画布的 getContext() 方法获得的一个“绘图环境”对象上

        var tCanvas = document.getElementById("canvasOne");
        var ct = tCanvas.getContext("2d");

        //因此可以通过该方法来检测浏览器是否支持canvas:
        function canvasSupport() {
            //检测是否支持canvas
            return !!document.createElement("canvas").getContext;
        }

绘制矩形

界面html如下所示:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
</head>
<body onload="draw('canvas');">
    <canvas id="canvas" width="400" height="300"></canvas>
    <script src="script.js"></script>
</body>
</html>

JavaScript如下所示:

    function draw(id) {
        var canvas = document.getElementById(id);
        if (canvas == null) {
            return false;
        }
        var context = canvas.getContext('2d');//取得上下文对象
        context.fillStyle = '#EEEEFF';//填充样式
        context.fillRect(0, 0, 400, 300);//填充矩形
        context.fillStyle = 'red';
        context.strokeStyle = 'blue';//图形边框的样式
        context.lineWidth = 1;//设置图形边框的宽度
        context.fillRect(50, 50, 100, 100);//填充矩形  
        context.strokeRect(50, 50, 100, 100);//绘制矩形边框
    }

效果图如下所示:

使用路径绘制圆形

JavaScript如下所示:

        function draw(id) {
            var canvas = document.getElementById(id);
            if (canvas == null) {
                return false;
            }
            var context = canvas.getContext('2d');
            context.fillStyle = '#EEEEFF';
            context.fillRect(0, 0, 400, 300);

            for (var i = 0; i < 10; i++) {
                context.beginPath();//开始创建路径
                //创建圆形路径 
                context.arc(i * 25,//绘制圆形的起点横坐标
                    i * 25,//绘制圆形的起点纵坐标
                    i * 10,//圆形半径
                    0,//开始角度
                    Math.PI * 2,//结束角度 
                    true/*是否按顺时针方向进行绘制*/);              
                context.closePath();//关闭路径
                context.fillStyle = 'rgba(255,0,0,0.25)';//设置绘制样式
                context.fill();//进行图形绘制

            }
        }

 

效果图如下所示:

未关闭路径绘制圆形

JavaScript如下所示:

        function draw(id) {
            var canvas = document.getElementById(id);
            if (canvas == null) {
                return false;
            }
            var context = canvas.getContext('2d');
            context.fillStyle = '#EEEEFF';
            context.fillRect(0, 0, 400, 300);

            for (var i = 0; i < 10; i++) {
                context.arc(i * 25, i * 25, i * 10, 0, Math.PI * 2, true);
                context.fillStyle = 'rgba(255,0,0,0.25)';
                context.fill();
            }
            
        }

 

效果图如下所示:

使用moveTo和LineTo方法绘制复杂线条

JavaScript如下所示:

        function draw(id) {
            var canvas = document.getElementById(id);
            if (canvas == null) {
                return false;
            }
            var context = canvas.getContext('2d');
            context.fillStyle = '#EEEEFF';
            context.fillRect(0, 0, 400, 300);
            var dx = 150,
                dy = 150,
                s = 100,
                x = Math.sin(0),
                y = Math.cos(0),
                dig = Math.PI / 15 * 11;
            context.beginPath();//需要使用moveTo将光标移动到所指定的直线起点
            context.fillStyle = 'rgb(100,255,100)';
            context.strokeStyle = 'rbg(0,0,100)';

            for (var i = 0; i < 30; i++) {
                x = Math.sin(i * dig);
                y = Math.cos(i * dig);
                context.lineTo(dx + x * s, dy + y * s);//绘制一条直线  (在直线起点和直线终点绘制)
            }
            context.closePath();
            context.fill();
            context.stroke();
        }

 

效果图如下所示:

使用bezierCurveTo绘制贝济埃曲线

JavaScript如下所示:

        function draw(id) {
            var canvas = document.getElementById(id);
            if (canvas == null) {
                return false;
            }
            var context = canvas.getContext('2d');
            context.fillStyle = '#EEEEFF';
            var dx = 150,
             dy = 150,
             s = 100,
             x = Math.sin(0),
             y = Math.cos(0),
             dig = Math.PI / 15 * 11;
            context.beginPath();
            context.globalCompositeOperation = 'red';
            context.fillStyle = 'rgb(100,255,100)';
            context.moveTo(dx, dy);//将光标移动到指定坐标点
            for (var i = 0; i < 30; i++) {
                x = Math.sin(i * dig);
                y = Math.cos(i * dig);
                //绘制贝济埃曲线   将当前坐标点到指定坐标点中间的贝济埃曲线追加到路径中
                context.bezierCurveTo(dx + x * s,//第一个控制点的横坐标
                    dy + y * s - 100,//第一个控制点的纵坐标
                    dx + x * s + 100,//第二个控制点的横坐标
                    dy + y * s,//第二个控制点的纵坐标
                    dx + x * s,//贝济埃曲线的终点横坐标
                    dy + y * s);//贝济埃曲线的终点纵坐标
            }
            context.closePath();
            context.fill();
            context.stroke();
        }

 

效果图如下所示:

绘制线性渐变

JavaScript如下所示:

        function draw(id) {
            var canvas = document.getElementById(id);
            if (canvas == null) {
                return false;
            }
            var context = canvas.getContext('2d');
            //创建线性渐变
            var g1 = context.createLinearGradient(0,//渐变起始地点的横坐标
                0,//渐变起始地点的纵坐标
                0,////渐变结束地点的横坐标
                300);//渐变结束地点的纵坐标
            //追加渐变的颜色
            g1.addColorStop(0,//设定颜色离开渐变起始点的偏移量  该参数的值是一个范围在0到1之间的浮点数  渐变起始点的偏移量为0  渐变结束点的偏移量为1
                'rgb(255,255,0)');//颜色值
            //因为是渐变   所以至少使用两次addColorStop
            g1.addColorStop(1, 'rgb(0,255,255)');
            context.fillStyle = g1;
            context.fillRect(0, 0, 400, 300);
          
            var g2 = context.createLinearGradient(0, 0, 300, 0);
            g2.addColorStop(0, 'rgba(0,0,255,0.5)');
            g2.addColorStop(1, 'rgba(255,0,0,0.5)');
            for (var i = 0; i < 10; i++) {
                context.beginPath();
                context.fillStyle = g2;//设置为渐变LinearGradient对象
                context.arc(i * 25, i * 25, i * 10, 0, Math.PI * 2, true);
                context.closePath();
                context.fill();
            }
        }

 

效果图如下所示:

绘制径向渐变

JavaScript如下所示:

        function draw(id) {
            var canvas = document.getElementById(id);
            if (canvas == null) {
                return false;
            }
            var context = canvas.getContext('2d');
            //绘制径向渐变
            var g1 = context.createRadialGradient(400,//渐变开始圆的圆心横坐标
                0,//渐变开始圆的圆心纵坐标
                0,//渐变开始圆的半径
                400,//渐变结束圆的圆心横坐标
                0,//渐变结束圆的圆心纵坐标
                400);//渐变结束圆的半径
            g1.addColorStop(0.1, 'rgb(255,255,0)');
            g1.addColorStop(0.3, 'rgb(255,0,255)');
            g1.addColorStop(1, 'rgb(0,255,255)');
            context.fillStyle = g1;
            context.fillRect(0, 0, 400, 300);           
            var g2 = context.createRadialGradient(250, 250, 0, 250, 250, 250, 300);
            g2.addColorStop(0.1, 'rgba(255,0,0,0.5)');
            g2.addColorStop(0.7, 'rgba(255,255,0,0.5)');
            g2.addColorStop(1, 'rgba(0,0,255,0.5)');
            for (var i = 0; i < 10; i++) {
                context.beginPath();
                context.fillStyle = g2;
                context.arc(i * 25, i * 25, i * 10, 0, Math.PI * 2, true);
                context.closePath();
                context.fill();
            }

        }

 

效果图如下所示:

利用坐标变换来绘制类似扑克牌的变形图形

JavaScript如下所示:

        function draw(id) {
            var canvas = document.getElementById(id);
            if (canvas == null) {
                return false;
            }
            var context = canvas.getContext('2d');
            context.fillStyle = '#eef';
            context.fillRect(0, 0, 400, 300);
            //移动坐标轴原点 
            context.translate(200,//将坐标轴原点向左移动多少个单位
                50); //将坐标轴原点向下移动多少个单位
            
            context.fillStyle = 'rgba(255,0,0,0.25)';
            for (var i = 0; i < 50; i++) {
                context.translate(25, 25);
                //将图形放大
                context.scale(0.95,//水平方向的放大倍数
                    0.95);//垂直方向的放大倍数
                context.rotate(Math.PI / 10);//将图形进行旋转
                context.fillRect(0, 0, 100, 50);
            }
        }

 

效果图如下所示:

利用坐标变换与路径结合使用来绘制星形图形

JavaScript如下所示:

        function draw(id) {
            var canvas = document.getElementById(id);
            if (canvas == null) {
                return false;
            }
            var context = canvas.getContext('2d');
            context.fillStyle = '#eef';
            context.fillRect(0, 0, 400, 300);
            context.translate(200, 50);
            for (var i = 0; i < 50; i++) {
                context.translate(25, 25);
                context.scale(0.95, 0.95);
                context.rotate(Math.PI / 10);
                create5Star(context);
                context.fill();
            }
        }
        function create5Star(context) {
            var dx = 100,
                dy = 0,
                s = 50;
            context.beginPath();
            context.fillStyle = 'rgba(255,0,0,0.5)';
            var x = Math.sin(0),
                y = Math.cos(0),
                dig = Math.PI / 5 * 4;

            for (var i = 0; i < 5; i++) {
                 x = Math.sin(i * dig);
                 y = Math.cos(i * dig);
                context.lineTo(dx + x * s, dy + y * s);
            }
            context.closePath();

        }

 

效果图如下所示:

利用矩阵变换来绘制彩虹

JavaScript如下所示:

        function draw(id) {
            var canvas = document.getElementById(id);
            if (canvas == null) {
                return false;
            }
            var context = canvas.getContext('2d');
            //定义颜色
            var colors = ['red', 'orange', 'yellow', 'green', 'blue', 'navy', 'purple'];
            context.lineWidth = 10;//定义线宽
            context.transform(1, 0, 0, 1, 100, 0);//矩阵转换
            for (var i = 0; i < colors.length; i++) {//循环绘制圆弧
                context.transform(1, 0, 0, 1, 0, 10);//定义每次向下移动10个像素的变换矩阵
                context.strokeStyle = colors[i];//设定颜色
                context.beginPath();
                context.arc(50, 100, 100, 0, Math.PI, true);//绘制圆弧
                context.stroke();
            }
        }

 

效果图如下所示:

使用setTransform方法绘制变形图形

JavaScript如下所示:

        function draw(id) {
            var canvas = document.getElementById(id);
            if (canvas == null) {
                return false;
            }
            var context = canvas.getContext('2d');
            //绘制红色长方形
            context.strokeStyle = 'red';
            context.strokeRect(30, 10, 60, 20);
            //绘制顺时针旋转45度的蓝色长方形
            var rad = 45 * Math.PI / 180;
            context.setTransform(Math.cos(rad), Math.sin(rad), -Math.sin(rad), Math.cos(rad), 0, 0);//定义顺时针旋转45的变换矩阵           
            context.strokeStyle = 'blue';
            context.strokeRect(30, 10, 60, 20);//绘制图形
            //绘制放大2.5倍后的绿色长方形
            context.setTransform(2.5, 0, 0, 2.5, 0, 0);//定义放大2.5倍的变换矩阵
            context.strokeStyle = 'green';
            context.strokeRect(30, 10, 60, 20);//绘制图形
            //将坐标原点向左移动40像素,向下移动80像素后绘制灰色长方形
            context.setTransform(1, 0, 0, 1, 40, 80);//定义将坐标原点向右移动40像素,向下移动80像素的矩阵
            context.strokeStyle = 'gray';
            context.strokeRect(30, 10, 60, 20);//绘制图形
        }

 

效果图如下所示:

图形结合的不同选项讲解

JavaScript如下所示:

        function draw(id) {
            var canvas = document.getElementById(id);
            if (canvas == null) {
                return false;
            }
            var context = canvas.getContext('2d');
            var oprtns = [
                'source-atop',//只绘制新图形中与原有图形重叠的部分与未被重叠覆盖的原有图形,新图形的其它部分变成透明
                'source-in',//只显示新图形中与原有图形相重叠的部分,新图形与原有图形的其它部分均变成透明
                'source-out',//只显示原图形与新图形不重叠的部分,新图形与原有图形的其它部分均变成透明
                'source-over',//新图形覆盖在原有图形之上
                'destination-atop',//只绘制原有图形中被新图形重叠覆盖的部分与新图形的其它部分,原有图形中的其它部分变成透明 ,不绘制新图形中与原有图形相重叠的部分
                'destination-in',//只显示原有图形中与新图形相重叠的部分,新图形与原有图形的其它部分均变成透明
                'destination-out',//只显示原有图形中与新图形不重叠的部分,新图形与原有图形的其它部分均变成透明
                'destination-over',//在原有图形之下绘制图形
                'lighter',//原有图形与新图形均绘制,重叠部分做加色处理
                'copy',//只绘制新图形,原有图形中未与新图形重叠的部分变成透明
                'xor'];//只绘制新图形中与原有图形不重叠的部分,重叠部分变成透明
            i = 7;//在原有图形之下绘制图形  (这里大家可以自己去试下其它选项  方便自己深入理解)
            context.fillStyle = 'blue';
            context.fillRect(10, 10, 60, 60);
            context.globalCompositeOperation = oprtns[i];
            context.beginPath();
            context.fillStyle = 'red';
            context.arc(60, 60, 30, 0, Math.PI * 2, false);
            context.fill();
        }

 

效果图如下所示:

给图形绘制阴影

JavaScript如下所示:

        function draw(id) {
            var canvas = document.getElementById(id);
            if (canvas == null) {
                return false;
            }
            var context = canvas.getContext('2d');
            context.fillStyle = '#eef';
            context.fillRect(0, 0, 400, 300);
            context.shadowOffsetX = 10;//阴影的横向位移量
            context.shadowOffsetY = 10;//阴影的纵向位移量
            context.shadowColor = 'rgba(100,100,100,0.5)';//阴影的颜色
            context.shadowBlur = 7.5;//阴影的模糊范围
            context.translate(0, 50);
            for (var i = 0; i < 3; i++) {
                context.translate(50, 50);
                create5Star(context);
                context.fill();
            }
        }
        function create5Star(context) {
            var dx = 100,
                dy = 0,
                s = 50,
                x = Math.sin(0),
                y = Math.cos(0),
                dig = Math.PI / 5 * 4;
            context.beginPath();
            context.fillStyle = 'rgba(255,0,0,0.5)';


            for (var i = 0; i < 5; i++) {
                x = Math.sin(i * dig);
                y = Math.cos(i * dig);
                context.lineTo(dx + x * s, dy + y * s);
            }
            context.closePath();

        }

 

效果图如下所示:

绘制图像

JavaScript如下所示:

        function draw(id) {
            var canvas = document.getElementById(id);
            if (canvas == null) {
                return false;
            }
            var context = canvas.getContext('2d');
            context.fillStyle = '#eef';
            context.fillRect(0, 0, 400, 300);
            var image = new Image();
            image.src = 'img/ctrip.gif';
            image.onload = function () {              
                for (var i = 0; i < 7; i++) {
                    context.drawImage(image,//img元素
                        0 + i * 50,//绘制时的图像的宽度
                        0 + i * 25,//绘制时的图像的高度
                        100,//绘制该图像在画布中的x坐标
                        100);//绘制该图像在画布中的y坐标
                }
            }
        }

 

效果图如下所示:

绘制图像时放大局部图像

JavaScript如下所示:

        function draw(id) {
            var canvas = document.getElementById(id);
            if (canvas == null) {
                return false;
            }
            var context = canvas.getContext('2d');
            context.fillStyle = '#eef';
            context.fillRect(0, 0, 400, 300);
            var image = new Image();
            image.src = 'img/ctrip.gif';//设置图像路径
            image.onload = function () {//绘制图像的函数
                var i = 0;
                //绘制原始图像
                context.drawImage(image,//img元素
                    0,//绘制时的图像的宽度
                    0,//绘制时的图像的高度
                    100,//绘制该图像在画布中的x坐标
                    100);//绘制该图像在画布中的y坐标
                //绘制将局部区域进行放大后的图像
                context.drawImage(image,//img元素
                    0,//源图像被复制区域在画布中的起始画布中的起始横坐标
                    0,//源图像被复制区域在画布中的起始画布中的起始纵坐标
                    50,//被复制区域的宽度
                    80,//被复制区域的高度
                    110,//复制后的目标图像在画布中的起始横坐标
                    0,//复制后的目标图像在画布中的起始纵坐标
                    100,//复制后的目标图像的宽度
                    100);//复制后的目标图像的高度
            }
        }

 

效果图如下所示:

图像平铺

JavaScript如下所示:

        function draw(id) {
            var canvas = document.getElementById(id);
            if (canvas == null) {
                return false;
            }
            var context = canvas.getContext('2d');
            var image = new Image();
            image.src = 'img/ctrip.gif';//设置图像路径
            image.onload = function () {
                var scale = 5,
                    n1 = image.width / scale,
                    n2 = image.height / scale,
                    n3 = canvas.width / n1,
                    n4 = canvas.height / n2;
                for (var i = 0; i < n3; i++) {
                    for (var j = 0; j < n4; j++) {
                        context.drawImage(image, i * n1, j * n2, n1, n2);
                    }
                }
            }
        }

 

效果图如下所示:

利用createPattern方法平铺图像

JavaScript如下所示:

        function draw(id) {
            var canvas = document.getElementById(id);
            if (canvas == null) {
                return false;
            }
            var context = canvas.getContext('2d');
            var image = new Image();
            image.src = 'img/ctrip.gif';//设置图像路径
            image.onload = function () {
                //no-repeat 不平铺
                //repeat-x  横方向平铺
                //repeat-y  纵方向平铺
                //repeat   全方向平铺
                var ptrn = context.createPattern(image, 'repeat');//创建填充样式,全方向平铺
                context.fillStyle = ptrn;//指定填充样式
                context.fillRect(0, 0, 400, 300);//填充画布
            }
        }

 

效果图如下所示:

图像裁剪

JavaScript如下所示:

        function draw(id) {
            var canvas = document.getElementById(id);
            if (canvas == null) {
                return false;
            }
            var context = canvas.getContext('2d');
            var gr = context.createLinearGradient(0, 400, 300, 0);
            gr.addColorStop(0, 'rgb(255,255,0)');
            gr.addColorStop(1, 'rgb(0,255,255)');
            context.fillStyle = gr;
            context.fillRect(0, 0, 400, 300);
            var image = new Image();
            image.src = 'img/ctripLogo.png';//设置图像路径
            image.onload = function () {
                var n = 0,
                    dx = 100,
                    dy = 0,
                    s = 150,
                    x = Math.sin(0),
                    y = Math.cos(0),
                    dig = Math.PI / 5 * 4;
                context.beginPath();
                context.translate(100, 150);
                for (var i = 0; i < 5; i++) {
                    x = Math.sin(i * dig);
                    y = Math.cos(i * dig);
                    context.lineTo(dx + x * s, dy + y * s);//创建一个五角星的路径
                }
                context.clip();//设置裁剪图像
                context.drawImage(image, -50, -150, 300, 300);

            }
        }

 

效果图如下所示:

将图像进行反显操作

JavaScript如下所示:

        function draw(id) {
            var canvas = document.getElementById(id);
            if (canvas == null) {
                return false;
            }
            var context = canvas.getContext('2d');
            var image = new Image();
            image.src = 'img/ctrip.gif';//设置图像路径
            image.onload = function () {
                context.drawImage(image, 0, 0);
                //获得图像中的像素
                var imageData = context.getImageData(0,//起点横坐标
                    0,//起点纵坐标
                    image.width,//获取区域的宽度
                    image.height);//获取区域的高度
                for (var i = 0,n=imageData.data.length; i < n; i+=4) {
                    imageData.data[i + 0] = 255 - imageData.data[i + 0];//red
                    imageData.data[i + 1] = 255 - imageData.data[i + 2];//red
                    imageData.data[i + 2] = 255 - imageData.data[i + 1];//red
                }
                //将像素的数据重新放置到图像中
                context.putImageData(imageData,//像素数组
                    0,//重绘图像的起点横坐标
                    0);//重绘图像的起点纵坐标
            }
        }

 

效果图如下所示:

绘制文字

JavaScript如下所示:

        function draw(id) {
            var canvas = document.getElementById(id);
            if (canvas == null) {
                return false;
            }
            var context = canvas.getContext('2d');
            context.fillStyle = '#00f';
            context.font = 'italic 30px sans-serif';//设置文字字体
            context.textBaseline = 'top';//设置文字垂直对齐方式
            context.fillText('示例文字', 0, 0);
            context.font = 'bold 30px sans-serif';
            context.strokeText('示例文字', 0, 50);

        }

 

效果图如下所示:

测量文字宽度

JavaScript如下所示:

        function draw(id) {
            var canvas = document.getElementById(id);
            if (canvas == null) {
                return false;
            }
            var context = canvas.getContext('2d');
            context.font = 'italic 20px sans-serif';
            var txt = '字符串的宽度为';//定义绘制文字
            var tml = context.measureText(txt);//获得文字宽度
            context.fillText(txt, 10, 30);//绘制文字 
            context.fillText(tml.width, tml.width + 10, 30);
            context.font = 'bold 30px sans-serif';//改变字体
            var tm2 = context.measureText(txt);//重新获得文字宽度
            context.fillText(txt, 10, 70);//重新绘制文字
            context.fillText(tm2.width, tm2.width + 10, 70);
        }

效果图如下所示:

posted @ 2015-06-06 22:06  静逸  阅读(3619)  评论(3编辑  收藏  举报