html5 canvas 学习

1.定义画布,取得画布上下文下文

 <canvas id="canvas"></canvas>

js:

var cvs = document.getElementById("canvas");
        var context = cvs.getContext('2d');
        cvs.width = 1000;
        cvs.height = 600;

2.绘制一条直线

context.moveTo(100, 100);
context.lineTo(300, 200);
context.strokeStyle="red";//笔刷颜色,填充颜色用 .fillStyle
context.lineWidth=10;//笔刷宽度
context.stroke();//填充用.fill()方法

如果要绘制多条线段 ,并且分别对线段指定样式,但最终显示都是最后指定的一个样式,这是因为canvas是状态绘制,所以对每个线段绘制可都应该用beginPath方法来告知是一个全新绘制就没有问题了

context.lineWidth = 10;

        context.beginPath();
        context.lineTo(100, 100);
        context.lineTo(300, 200);
        context.lineTo(100, 300);
        context.strokeStyle = "#003399";
        context.stroke();

        context.beginPath();
        context.moveTo(300, 100);
        context.lineTo(600, 200);
        context.lineTo(300, 300);
        context.strokeStyle = "#330022";
        context.stroke();

以上线段没有首尾闭合,如要闭合添加context.closePath()即可。

注意,context.beignPath()与context.closePath()不是一定要成对出现的,只要线段间需要闭合时才使用closePath

3.画矩形方法

context.rect(100, 100, 200, 200);
context.fill()//或context.stroke()

context.fillRect(100, 100, 200, 200);

context.strokeRect(100, 100, 200, 200);

对fillStyle样式可以指定颜色,还可以指定透明度:

        context.lineWidth = 10;
        context.beginPath();
        context.fillStyle = "red";
        context.fillRect(100, 100, 300, 300);
       
        context.beginPath();
        context.fillStyle = "rgba(0, 255, 0, 0.5)";
        context.fillRect(200, 200, 300, 300);

 

4.直线两端的样式:context.lineCap="round",值分别可以butt(默认),round,square,注意使用round和square会比默认的多出来一小段长度,

直线与直线相交的形式:context.lineJoin,值分别:miter(默认)|bevel|round .如果绘制的角很尖时,还需要考虑另一个值:  cxt.miterLimit = 20;默认值为10

5.画五角形,函数如下:

function drawStar(cxt, x, y, outerR, innerR, rot) {
             cxt.beginPath();
             for (var i = 0; i < 5; i++) {
                 cxt.lineTo(Math.cos((18+i*72-rot)/180*Math.PI)*outerR+x,
                 -Math.sin((18+i*72-rot)/180*Math.PI)*outerR+y);
                 cxt.lineTo(Math.cos((54 + i * 72 - rot) / 180 * Math.PI) * innerR + x,
                     -Math.sin((54 + i * 72 - rot) / 180 * Math.PI) * innerR + y);
             }
             cxt.closePath();

             cxt.fillStyle = "#fb3";
             cxt.strokeStyle = "#fd5";
             cxt.lineWidth = 3;
             cxt.lineJoin = "rount";

             cxt.fill();
             cxt.stroke();
         }

在画布上添加200个五角星

for (var i = 0; i < 200; i++) {
                 var r = Math.random() * 10 + 10;
                 var x = Math.random() * cvs.width;
                 var y = Math.random() * cvs.height;
                 var a = Math.random() * 360;
                 drawStar(context, x, y, r, r / 2.0, a);
             }

 6.图形变换:tanslate,rotate,scale

如果对图形时行多次变换,最终结果可能会与实现想象中有差异,最好使用context.save()和context.restore(),这里context.save();和context.restore();是两个相互匹配出现的,作用是用来保存画布的状态和取出保存的状态的

        context.translate(100, 0),是向右移动100个像素,如果没有save和restore,会对多次出现的平移进行叠加

context.scale(x,y),缩放使用可注意,它不仅对图形大小时行缩放,还会对边框和起点坐标也会一起缩放,所以使用scale一定要注意。

如果绘制起点设置在(0,0)坐标开始绘制,那缩放将对起点不起任何作用,这样就可能可保证起点不发生改变,此时tanslate移动起点是正确的显示器。

通过学习图形变换,把显示200星星的实例修改一下,使用图形变换的方式显示出来,不过由于使用缩放方法会使描边也发生缩放,所以这里就去掉星星的边框。

 

 context.fillStyle = "#fb3";
        context.lineJoin = "rount";
        for (var i = 0; i < 200; i++) {
            var r = Math.random() * 10 + 10;
            var x = Math.random() * cvs.width;
            var y = Math.random() * cvs.height;
            var a = Math.random() * 360;
            drawStar(context, x, y, r, a);
        }

        function drawStar(context,x,y,r,rot) {
            context.save();
            context.translate(x, y);
            context.rotate(rot / 180 * Math.PI);
            context.scale(r, r);
            starPath(context);
            context.fill();
            context.restore();
        }
        function starPath(context) {
            context.beginPath();
            for (var i = 0; i < 5; i++) {
                context.lineTo(Math.cos((18 + i * 72) / 180 * Math.PI) ,
                -Math.sin((18 + i * 72 ) / 180 * Math.PI) );
                context.lineTo(Math.cos((54 + i * 72) / 180 * Math.PI) * 0.5,
                    -Math.sin((54 + i * 72 ) / 180 * Math.PI) * 0.5);
            }
            context.closePath();
        }

除了用translate,rotate,scale对图形变换外,还可以使用transform一次设定这几个方法的参数 :transform(a,b,c,d,e,f) ,如果参数设置成(1,0,0,1,0,0)对图形的变化不会产生任何变化。参数:a

 

、d是控件水平和垂直缩放的,b和c是倾斜,e和f是位移。多个 transform()一起使用会是效果级联叠加,如果想恢复到最初状态开始可以使用setTransform();

 

7.渐变:

线性渐变:

 

 var linearGradient = context.createLinearGradient(0, 0, 800, 0);
        linearGradient.addColorStop(0.0, "red");
        linearGradient.addColorStop(1.0, "blue");

        context.fillStyle = linearGradient;
        context.fillRect(0, 0, 800, 800);

 

径向渐变:

        var linearGradient = context.createRadialGradient(400, 400, 0,400,400,800);
        linearGradient.addColorStop(0.0, "red");
        linearGradient.addColorStop(1.0, "blue");

        context.fillStyle = linearGradient;
        context.fillRect(0, 0, 800, 800);    
为了图像颜色鲜艳可以添加多个addColorStop
图案填充:
        var img = new Image();
        img.src = "imgs/head.jpg";
        img.onload = function () {
            var pattern = context.createPattern(img,"repeat");
            
            context.fillStyle = pattern;
            context.fillRect(0, 0, 800, 800);
        };

画布作为图案填充:

  var pattern = context.createPattern(drawRect(), "repeat");
        context.fillStyle = pattern;
        context.fillRect(0, 0, 800, 800);

        function drawRect() {
            var v = document.createElement("canvas");
            v.width = 50;
            v.height = 50;
            var c = v.getContext('2d');
            c.lineWidth = 5;
            c.strokeRect(0, 0, 45, 45);
            return v;
        }

还可以使用视频来作为图案填充

8.画园角矩形

        var cvs = document.getElementById("canvas");
        var context = cvs.getContext('2d');
        cvs.width = 1000;
        cvs.height = 700;
       
        context.transform(1, 0, 0, 1, 100, 100);
        drawRoundRect(350, 150, 20);
        

        context.stroke();
        function drawRoundRect( w, h, r) {
            
            context.beginPath();
            context.arc(r, r, r, Math.PI, 3 * Math.PI / 2);
            context.arc(w - r, r, r, Math.PI * 3 / 2, 0);
            context.arc(w - r, h - r, r, 0, Math.PI / 2);
            context.arc(r, h - r, r, Math.PI / 2, Math.PI);
            context.closePath();
        }

9.曲线,不细说了,可以查看贝塞尔曲线(二次,三次),网上有直接生成三次贝塞尔曲线的网页

 

10.字体:

context.font = "bold 40px 雅黑";
context.fillText("我是一个兵", 200, 200);

context.measureText("我是一个兵").width,可以取宽度

11.阴影

context.shadowBlur = 5;
        context.shadowOffsetX = 20;
        context.shadowOffsetY = 20;
        context.shadowColor = "gray";

12.生成100个小球

var cvs = document.getElementById("canvas");
        var context = cvs.getContext('2d');
        cvs.width = 1000;
        cvs.height = 700;
        context.globalAlpha = 0.7;
        for (var i = 0; i < 100; i++) {
            var x = Math.random() * cvs.width;
            var y = Math.random() * cvs.height;
            var r = Math.random() * 50;
            var cr = Math.floor(Math.random() * 255);
            var g = Math.floor(Math.random() * 255);
            var b = Math.floor(Math.random() * 255);
            context.fillStyle = "rgb(" + cr + "," + g + "," + b + ")";
            context.beginPath();
            context.arc(x, y, r, 0, 2 * Math.PI);
            context.fill();
        }
context.globalAlpha 是透明度,context.globalCompositeOperation 属性设置或返回如何将一个源(新的)图像绘制到目标(已有)的图像上
描述
source-over 默认。在目标图像上显示源图像。
source-atop 在目标图像顶部显示源图像。源图像位于目标图像之外的部分是不可见的。
source-in 在目标图像中显示源图像。只有目标图像内的源图像部分会显示,目标图像是透明的。
source-out 在目标图像之外显示源图像。只会显示目标图像之外源图像部分,目标图像是透明的。
destination-over 在源图像上方显示目标图像。
destination-atop 在源图像顶部显示目标图像。源图像之外的目标图像部分不会被显示。
destination-in 在源图像中显示目标图像。只有源图像内的目标图像部分会被显示,源图像是透明的。
destination-out 在源图像外显示目标图像。只有源图像外的目标图像部分会被显示,源图像是透明的。
lighter 显示源图像 + 目标图像。
copy 显示源图像。忽略目标图像。
source-over 使用异或操作对源图像与目标图像进行组合。

 

11.剪辑区域

context.clip();

12.非零环绕原则,

context.beginPath();
        context.arc(400, 400, 300, 0, 2 * Math.PI,true);
        context.arc(400, 400, 150, 0, 2 * Math.PI);
        context.closePath();
        context.fillStyle = "red";
        context.shadowColor = "gray";
        context.shadowOffsetX = 10;
        context.shadowOffsetY = 10;
        context.shadowBlur = 5;
        context.fill();

 

非零环绕规则:对于路径中指定范围区域,从该区域内部画一条足够长的线段,使此线段的完全落在路径范围之外。


非零环绕规则计数器:
然后,将计数器初始化为0,每当这个线段与路径上的直线或曲线相交时,就改变计数器的值,如果是与路径顺时针相交时,那么计数器就加1, 如果是与路径逆时针相交时,那么计数器就减1.
如果计数器始终不为0,那么此区域就在路径范围里面,在调用fill()方法时,浏览器就会对其进行填充。如果最终值是0,那么此区域就不在路径范围内,浏览器就不会对其进行填充。

 

13.事件:

var ball = [];
var cvs = document.getElementById("canvas");
        var context = cvs.getContext('2d');
        cvs.width = 1000;
        cvs.height = 700; window.onload
=function() { for (var i = 0; i < 10; i++) { ball[i] = { x: Math.random() * cvs.width, y:Math.random()*cvs.height, r:Math.random()*100 }; } draw(); cvs.addEventListener("mouseup", function (e) { e.stopPropagation(); var x =e.clientX- cvs.getBoundingClientRect().left; var y = e.clientY - cvs.getBoundingClientRect().top; for (var i = 0; i < 10; i++) { context.beginPath(); context.arc(ball[i].x, ball[i].y, ball[i].r, 0, 2 * Math.PI); if(context.isPointInPath(x, y)){ context.fillStyle = "red"; context.fill(); } } }); } function draw() { for (var i = 0; i < 10; i++) { context.beginPath(); context.arc(ball[i].x, ball[i].y, ball[i].r, 0, 2 * Math.PI); context.fillStyle = "gray"; context.fill(); } }

 

14.如果想偷懒,当然可以找一些现成的图形库,直接应用就可以,比如RGraph是一个使用HTML5 Canvas标签实现的图表制作Library。利用该Library生成的Chart具有可交互性,当鼠标点击或移过时会显示相应的信息,可以动态加载Chart或对特殊点进行缩放。当前支持的图表类型包括:

  • bar、pie、donut、gantt、radar、funnel、bi-polar charts
  • line and scatter graphs
  • LED display
  • meter
  • odometer
  • progress bar

http://www.rgraph.net/download

 

15.最后来一个动画:

 var bgcolor = "#000";
            var balls = [];
            var canvas = document.getElementById("canvas");
            var context = canvas.getContext('2d');
            canvas.width = 1000,
            canvas.height = 700;
            //添加小球
            getBall();
            setInterval(function () {
                    drawBall();
            }, 50);

            function drawBall() {
                context.globalCompositeOperation = "lighter";
                context.clearRect(0, 0, canvas.width, canvas.height);
                //画背景色
                context.beginPath();
                context.fillStyle = bgcolor;
                context.fillRect(0, 0, canvas.width, canvas.height);
                
                //画球
                for (var i = 0; i < balls.length; i++) {
                    var ball = balls[i];
                    if ((ball.x - ball.r) < 0 || (ball.x + ball.r) >= canvas.width) {
                        ball.vx = -ball.vx;
                    }
                    if ((ball.y - ball.r) <= 0 || (ball.y + ball.r) >= canvas.height) {
                        ball.vy = -ball.vy;
                    }
                    ball.x += ball.vx;
                    ball.y += ball.vy;

                    context.beginPath();
                    context.arc(ball.x, ball.y, ball.r, 0, 2 * Math.PI);
                    context.closePath();
                    context.fillStyle = ball.color;
                    context.fill();
                }


            }
            function getBall() {
                for (var i = 0; i < 100; i++) {
                    var r =Math.random() * 40 + 10;
                    var x =Math.random() * (canvas.width-2*r)+r;
                    var y = Math.random() * (canvas.height - 2 * r)+ r;
                    var vx = (Math.random() * 5 + 2) * Math.pow(-1, Math.floor(Math.random() * 100));
                  var  vy = (Math.random() * 5 + 2) * Math.pow(-1, Math.floor(Math.random() * 100));
                    var R = Math.floor(Math.random() * 255);
                    var G = Math.floor(Math.random() * 255);
                    var B = Math.floor(Math.random() * 255);
                    var color = "rgba(" + R + "," + G + "," + B + ","+Math.random()+")";
                    balls[i] = { x: x, y: y, r: r, vx: vx, vy: vy, color: color };
                }
            }

 

 

posted @ 2016-01-30 13:26  lunawzh  阅读(289)  评论(0编辑  收藏  举报