canvas基础学习笔记(五)

canvas高级内容

一、阴影

context.shadowColor="gray";//指定阴影的颜色
context.shadowOffsetX=-20;//指定阴影的位移值
context.shadowOffsetY=-20;//指定阴影的位移值
context.shadowBlur=5;//描述阴影模糊的程度(值越大越模糊)
示例代码如下:

<script type="text/javascript">
    window.onload=function(){
       var canvas=document.getElementById('canvas');
      
       canvas.width=1024;
       canvas.height=800;
    
       var context=canvas.getContext('2d');
       
       context.fillStyle="#058";
       context.shadowColor="gray";//可以使用任意的css可以接受的样式值,包括使用rgba设置半透明色
       //context.shadowOffsetX=20;
       //context.shadowOffsetY=20;
       //负值时阴影方向会相反
       context.shadowOffsetX=-20;
       context.shadowOffsetY=-20;
       context.shadowBlur=5;//越大越模糊

       context.fillRect(200,200,400,400);
      }
</script>

二、global属性

1.globalAlpha

context.globalAlpha=1;默认值,在这种情况下默认绘制的图形都不具有透明度,即后绘制的图形会盖住之前绘制的图形。示例如下:

<script type="text/javascript">
    window.onload=function(){
       var canvas=document.getElementById('canvas');
      
       canvas.width=1200;
       canvas.height=700;
    
       var context=canvas.getContext('2d');

       context.globalAlpha=0.5;//不加此句时后绘制的圆会盖住之前绘制的
       //画出100个圆
       for(var i=0;i<100;i++){
        var R=Math.floor(Math.random()*255);
        var G=Math.floor(Math.random()*255);
        var B=Math.floor(Math.random()*255);

        context.fillStyle="rgb("+R+","+G+","+B+")";

        context.beginPath();
        context.arc(Math.random()*canvas.width,Math.random()*canvas.height,Math.random()*100,0,Math.PI*2);
        context.fill();
       }
      }
</script>

2.globalCompositeOperation(描述绘制的图形在重叠时所产生的效果)

context.globalCompositeOperation="source-over";//后绘制的图形会盖住之前绘制的图形
context.globalCompositeOperation="destination-over";//之前绘制的图形会盖住之后绘制的图形
示例如下:

<script type="text/javascript">
    window.onload=function(){
       var canvas=document.getElementById('canvas');
      
       canvas.width=800;
       canvas.height=800;
    
       var context=canvas.getContext('2d');

      context.fillStyle="blue";
      context.fillRect(100,200,400,400);

      //context.globalCompositeOperation="source-over";
      context.globalCompositeOperation="destination-over";
      context.fillStyle="red";

      context.beginPath();
      context.moveTo(400,300);
      context.lineTo(650,700);
      context.lineTo(150,700);
      context.closePath();
      context.fill();
  }
</script>

此外,其他globalCompositeOperation属性的属性值如下:
source-over、source-atop、source-in 、source-out ;destination-over 、destination-atop 、destination-in 、destination-out;lighter、 copy、 xor。示例代码如下:

<body >
 <canvas id="canvas" style="border: 1px solid #aaa;display: block;margin: 50px auto">
 当前浏览器不支持canvas,请更换浏览器后再试
 </canvas>
 <div id="buttons">
   <a href="#">source-over</a>
   <a href="#">source-atop</a>
   <a href="#">source-in</a>
   <a href="#">source-out</a>
   <a href="#">destination-over</a>
   <a href="#">destination-atop</a>
   <a href="#">destination-in</a>
   <a href="#">destination-out</a>
   <a href="#">lighter</a>
   <a href="#">copy</a>
   <a href="#">xor</a>
 </div>

<script type="text/javascript">
  window.onload=function(){
    draw("source-over");
    var buttons=document.getElementById("buttons").getElementsByTagName("a");
    for(var i=0;i<buttons.length;i++){
      buttons[i].onclick=function(){
        draw(this.text);
        return false;
      }
    }
  }

    function draw(compositeStyle){
      var canvas=document.getElementById('canvas');
      canvas.width=1200;
      canvas.height=800;
      var context=canvas.getContext('2d');

      context.clearRect(0,0, canvas.width,canvas.height);

      //draw title
      context.font="bold 40px Arial";
      context.textAlign="center";
      context.textBaseline="middle";
      context.fillStyle="#058";
      context.fillText("globalCompositeOperation="+compositeStyle,canvas.width/2,60);

      //draw a rect
      context.fillStyle="blue";
      context.fillRect(300,150,500,500);

      //drae a triangle
      context.globalCompositeOperation=compositeStyle;
      context.fillStyle="red";
      context.beginPath();
      context.moveTo(700,250);
      context.lineTo(1000,750);
      context.lineTo(400,750);
      context.closePath();
      context.fill();
  }
</script>

三、clip和剪辑区域

1. context.clip();此函数与路径规划函数一起使用,例如:lineTo、arc、贝塞尔曲线等等。示例代码如下:

<script type="text/javascript">
    window.onload=function(){
       var canvas=document.getElementById('canvas');
      
       canvas.width=800;
       canvas.height=800;
    
       var context=canvas.getContext('2d');
       //设置画布颜色
       context.beginPath();
       context.fillStyle="black";
       context.fillRect(0,0,canvas.width,canvas.height)

       context.beginPath();
       context.arc(400,400,150,0,Math.PI*2);
       context.fillStyle="#fff";
       context.fill();
       context.clip();
       
       context.font="bold 140px Arial";
       context.textAlign="center";
       context.textBaseline="middle";
       context.fillStyle="#058";
       context.fillText("CANVAS",canvas.width/2,canvas.height/2);    
  }
</script>

2.小实例(圆形探照灯制作)

<script type="text/javascript">
  var searchLight={x:400,y:400,radius:150,vx:Math.random()*5+10,vy:Math.random()*5+10,}//vx vy代表移动的速度

    window.onload=function(){
       var canvas=document.getElementById('canvas');
      
       canvas.width=800;
       canvas.height=800;
    
       var context=canvas.getContext('2d');
       
       //动画基础
       setInterval(function(){
        draw(context);
        update(canvas.width,canvas.height);
       },40);
    }

    function draw(cxt){
      var canvas=cxt.canvas;
      cxt.clearRect(0,0,canvas.width,canvas.height);//清空画布

      cxt.save();
      //填充画布为黑色
      cxt.beginPath();
      cxt.fillStyle="black";
      cxt.fillRect(0,0,canvas.width,canvas.height);
      //画出填充区域
      cxt.beginPath();
      cxt.arc(searchLight.x,searchLight.y,searchLight.radius,0,Math.PI*2);
      cxt.fillStyle="#fff";
      cxt.fill();
      cxt.clip();
      //撰写文字
      cxt.font="bold 140px Arial";
      cxt.textAlign="center";
      cxt.textBaseline="middle";
      cxt.fillStyle="#058";
      cxt.fillText("CANVAS",canvas.width/2,canvas.height/4);
      cxt.fillText("CANVAS",canvas.width/2,canvas.height/2);
      cxt.fillText("CANVAS",canvas.width/2,canvas.height*3/4);

      cxt.restore();
    }

    function update(canvasWidth,canvasHeight){
      searchLight.x+=-searchLight.vx;
      searchLight.y+=searchLight.vy;

      if(searchLight.x-searchLight.radius<=0){
        searchLight.vx=-searchLight.vx;
        searchLight.x=searchLight.radius;
      }

      if(searchLight.x+searchLight.radius>=canvasWidth){
        searchLight.vx=-searchLight.vx;
        searchLight.x=canvasWidth-searchLight.radius;
      }
      
      if(searchLight.y-searchLight.radius<=0){
        searchLight.vy=-searchLight.vy;
        searchLight.y=searchLight.radius;
      }
      
       if(searchLight.y+searchLight.radius>=canvasHeight){
        searchLight.vy=-searchLight.vy;
        searchLight.y=canvasHeight-searchLight.radius;
      }
    }
</script>

四、路径方向和剪纸效果

1.路径方向(非零环绕原则)

路径示意图.jpg

如上图,将图形的绘制路径首尾相接并标明方向,然后从某个区域由区域内到外画出一个箭头,两个箭头方向相加不为0则染色,为0则不染色。下面以一个圆环的绘制为例:

圆环路径示意图.jpg

示例代码如下:

<script type="text/javascript">
 
    window.onload=function(){
       var canvas=document.getElementById('canvas');
      
       canvas.width=800;
       canvas.height=800;
    
       var context=canvas.getContext('2d');
       
       //绘制圆环
       context.beginPath();
       context.arc(400,400,300,0,Math.PI*2,false);
       context.arc(400,400,150,0,Math.PI*2,true);
       context.closePath();

       context.fillStyle="#058";
       context.shadowColor="gray";
       context.shadowOffsetX=10;
       context.shadowOffsetY=10;
       context.shadowBlur=10;
       context.fill();
    }
</script>

2.剪纸效果(需明确哪个位置染色,哪个位置不染色)

示例代码如下:

<script type="text/javascript">
 
    window.onload=function(){
       var canvas=document.getElementById('canvas');
      
       canvas.width=800;
       canvas.height=800;
    
       var context=canvas.getContext('2d');
       
       //绘制
       context.beginPath();
       context.rect(100,100,600,600);//顺时针
       pathRect(context,200,200,400,200);//逆时针
       pathTriangle(context,300,450,150,650,450,650);
       context.arc(550,550,100,0,Math.PI*2,true);//逆时针
       context.closePath();

       context.fillStyle="#058";
       context.shadowColor="gray";
       context.shadowOffsetX=10;
       context.shadowOffsetY=10;
       context.shadowBlur=10;
       context.fill();
    }
  
  function pathRect(cxt,x,y,width,height){
    cxt.moveTo(x,y);
    cxt.lineTo(x,y+height);
    cxt.lineTo(x+width,y+height);
    cxt.lineTo(x+width,y);
    cxt.lineTo(x,y);
  }
  function pathTriangle(cxt,x1,y1,x2,y2,x3,y3){
    cxt.moveTo(x1,y1);
    cxt.lineTo(x2,y2);
    cxt.lineTo(x3,y3);
    cxt.lineTo(x1,y1);
  }
</script>

五、使用canvas交互

isPointInPath 是canvas中内置的点击检测函数
context.isPointInPath(x,y)看传入的点(x,y)是否在当前规划的路径内。下边的例子是绘制10个小球,当点击小球时它的颜色由蓝色变为红色,示例代码如下:

<script type="text/javascript">
  var balls=[];
  var canvas=document.getElementById('canvas');
  var context=canvas.getContext('2d');

    window.onload=function(){
    canvas.width=800;
    canvas.height=800;
    for(var i=0;i<10;i++){
      var aBall={x:Math.random()*canvas.width,
          y:Math.random()*canvas.height,
          r:Math.random()*50+20};
          balls[i]=aBall;
    }
    draw();
    canvas.addEventListener("mouseup",detect);//用canvas的addEventListener方法创建事件
  }

    function draw(){
      //一次for循环遍历balls数组
      for(var i=0;i<balls.length;i++){
        context.beginPath();
        context.arc(balls[i].x,balls[i].y,balls[i].r,0,Math.PI*2);

        context.fillStyle="#058";
        context.fill();
      }
    }

    function detect(event){
      //获得鼠标点击在canvas中位置的方法
      var x=event.clientX-canvas.getBoundingClientRect().left;//鼠标坐标基于Web文档的横向距离减去canvas画布离整个文档左侧的距离
      var y=event.clientY-canvas.getBoundingClientRect().top;

      for(var i=0;i<balls.length;i++){
        context.beginPath();
        context.arc(balls[i].x,balls[i].y,balls[i].r,0,Math.PI*2);

        if(context.isPointInPath(x,y)){
          context.fillStyle="red";
          context.fill();
        }
      }
    }
</script>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容