<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 48,comments - 156,trackbacks - 0

    一、狀態(tài)及其保存和恢復(fù)

    在這一節(jié)開始之前,我們要先理解一下什么是狀態(tài)以及狀態(tài)的保存和恢復(fù)。玩過 MFC 編程的人經(jīng)常能碰到這樣的代碼:

    pOldPen=pDC->SelectObject(pNewPen)

    我們?cè)谶x擇一個(gè)新畫筆對(duì)象的同時(shí),總是要保存住舊畫筆對(duì)象,為什么要這樣做呢?因?yàn)樾庐嫻P對(duì)象只是臨時(shí)用一下,等用完了,我們想恢復(fù)到原來的畫筆配置時(shí),如果舊的配置事先沒有被保存,這些配置就丟失了,也就沒辦法恢復(fù)了。

    在 HTML5 繪圖中,某一刻的狀態(tài)就是當(dāng)前這一刻上下文對(duì)象的一系列屬性的配置值,只是,決定一個(gè)畫筆狀態(tài)的屬性比較少,如顏色、粗細(xì)、線型之類的,而確定上下文狀態(tài)的屬性比較多,包括下面這些:

    1、當(dāng)前上下文對(duì)象的移動(dòng)、旋轉(zhuǎn)、縮放配置

    2、當(dāng)前上下文對(duì)象的 strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation 屬性值

    3、當(dāng)前上下文對(duì)象的裁剪路徑配置

    上面這一系列配置決定了當(dāng)前這一刻上下文對(duì)象的狀態(tài),其中移動(dòng)、旋轉(zhuǎn)、縮放、globalCompositeOperation(組合)、裁剪下面我們馬上會(huì)講到。

     

    二、狀態(tài)的保存與恢復(fù)

    上面我們說某一刻的狀態(tài)由那么多屬性決定,我們要保存這一刻的狀態(tài)就要把這些屬性值一個(gè)一個(gè)都保存,恢復(fù)的時(shí)候在一個(gè)一個(gè)都設(shè)置回去,那也太麻煩了。確實(shí)是這樣的,所以上下文對(duì)下提供了了兩個(gè)簡(jiǎn)單的方法,對(duì)狀態(tài)進(jìn)行保存和恢復(fù),他們是:

    save( ) 和 restore( )

    save 和 restore 方法可以多次調(diào)用,每調(diào)用一次 save 方法,調(diào)用時(shí)的狀態(tài)(即一系列屬性值)就壓入一個(gè)棧中。

    每調(diào)用一次 restore 方法,最后一次 save 的狀態(tài)就被恢復(fù),即出棧。

    想象一下彈匣,第一顆被發(fā)射出去的子彈,總是最后一個(gè)被壓入彈匣的。

     

    三、變型

    1、移動(dòng):translate(dx,dy)

    這個(gè)方法看上去很簡(jiǎn)單,其實(shí)它包含了一定的數(shù)學(xué)含義,你可以認(rèn)為是整個(gè)坐標(biāo)系的原點(diǎn)發(fā)生了移動(dòng),新坐標(biāo)系下任意一點(diǎn)(x,y)相當(dāng)于原坐標(biāo)系下的坐標(biāo)為:

    x'=x+dx
    y'=y+dy

    如果我們調(diào)用 ctx.translate(5,8) 改變上下文對(duì)象的坐標(biāo)系狀態(tài),然后在新狀態(tài)下的點(diǎn)(3,2)繪圖,相當(dāng)于圖像被繪制到了原狀態(tài)下的點(diǎn)(8,10)處,即

    x'=5+3=8
    y'=5+2=10

    也許你會(huì)問,為什么要那么麻煩,直接在(8,10)處繪制比行嗎?比如把

    ctx.translate(5,8)
    ctx.drawImage(img,3,2)

    改成

    ctx.drawImage(img,8,10)

    這樣不是更簡(jiǎn)單、更直接嗎?

    我的理解是,移動(dòng)更多的情況下是為其他圖形變換服務(wù)的,恰當(dāng)?shù)母淖冏鴺?biāo)原點(diǎn)可以讓圖形學(xué)計(jì)算更好理解,并帶來很大方便,下面我舉個(gè)簡(jiǎn)單的例子,假如:

    有一條線段 ,是 x 軸正向上的一小段

    y = 0 (1 <= x <= 3),

    如果以坐標(biāo)原點(diǎn)為圓心,逆時(shí)針旋轉(zhuǎn)90度,則線段與 y 軸正向重合,旋轉(zhuǎn)后的線段為:

    x = 0 (1 <= y <= 3)

    但是我們不可能每次旋轉(zhuǎn)都以原點(diǎn)為圓心進(jìn)行旋轉(zhuǎn),假如我們以線段的一個(gè)端點(diǎn)(1,0)為圓心進(jìn)行旋轉(zhuǎn),我們?cè)趺床拍艿玫叫D(zhuǎn)后線段上每一點(diǎn)的坐標(biāo)值呢?其實(shí)這個(gè)過程可以分為三步:

    第一步:移動(dòng)原點(diǎn)坐標(biāo)到(1,0),新的線段依然在 x 軸上,但是方程變?yōu)榱耍簓 = 0 (0 <= x <= 2)

    第二步:以新坐標(biāo)系的原點(diǎn)為圓心進(jìn)行旋轉(zhuǎn),得到新坐標(biāo)系下的線段 x = 0 (0 <= y <= 2)

    第三步:將新坐標(biāo)系的原點(diǎn)移動(dòng)到新坐標(biāo)系下(-1,0)處,即將原點(diǎn)恢復(fù)到原來的位置,此時(shí)的線段為:x = 0 (0 <= y <= 2)

    第三步所得到的線段就是最后需要繪制的線段。

    從這個(gè)例子我們可以看出來,即使在這么簡(jiǎn)單的情況下,如果不移動(dòng)坐標(biāo)原點(diǎn)來直接計(jì)算旋轉(zhuǎn)后的圖形,也是比較困難的。

    提示當(dāng)你移動(dòng)坐標(biāo)原點(diǎn)之前,千萬別忘了保存狀態(tài),當(dāng)然,繪制完畢后也別放了恢復(fù)狀態(tài)。

    2、縮放 scale(sx, sy)

    這個(gè)同樣很簡(jiǎn)單,sx, sy 是縮放比例因子,縮放后新坐標(biāo)系下任意一點(diǎn) (x,y) 相當(dāng)于原坐標(biāo)系下的坐標(biāo)為:

    x' = x * sx
    y' = y * sy

    同樣,改變坐標(biāo)系統(tǒng)總是不要忘記保存和恢復(fù)狀態(tài)

    3、旋轉(zhuǎn) rotate(A)

    angle 是旋轉(zhuǎn)角度,旋轉(zhuǎn)后新坐標(biāo)系下任意一點(diǎn) (x,y) 相當(dāng)于原坐標(biāo)系下的坐標(biāo)為:

    x' = x cosA - y sinA
    y' = x sinA + y cosA

    同樣,改變坐標(biāo)系統(tǒng)總是不要忘記保存和恢復(fù)狀態(tài)

    4、變形 transform(m11, m12, m21, m22, dx, dy)

    其實(shí)前面講的移動(dòng)、縮放、旋轉(zhuǎn)都是變形的特例,transform 方法的六個(gè)參數(shù)組成了一個(gè)變形矩陣,如下

    m11 m21 dx
    m12 m22 dy
    0 0 1

    調(diào)用 transform 方法就相當(dāng)于用這些參數(shù)為上下文對(duì)象設(shè)置了新的變形矩陣,關(guān)于變形矩陣的具體內(nèi)容可以參照圖形學(xué)相關(guān)資料,下面給出幾個(gè)簡(jiǎn)單特例:

    移動(dòng) translate(dx,dy):相當(dāng)于 transform(1,0,0,1,dx,dy)

    縮放 scale(sx,xy):相當(dāng)于 transform(sx,0,0,sy,0,0)

    旋轉(zhuǎn) rotate(A):相當(dāng)于 transform(cosA,sinA,-sinA,cosA,0,0)

    以 (dx,dy) 為基準(zhǔn)點(diǎn)旋轉(zhuǎn)角度 A:transform(cosA, sinA, -sinA, cosA, dx(1-cosA) + dysinA, dy(1-cosA) - dxsinA)

    以 (dx,dy) 為基準(zhǔn)點(diǎn)進(jìn)行 (sx,sy)比例縮放:transform(sx, 0, 0, sy, dx(1-sx), dy(1-sy))

    還有很多其他更復(fù)雜的變形,大家可以參考圖形學(xué)相關(guān)資料。

    下面給出一個(gè)基準(zhǔn)點(diǎn)變形的例子,鼠標(biāo)在圖像上的某點(diǎn)保持按下狀態(tài),圖像就會(huì)以該點(diǎn)為基準(zhǔn)點(diǎn)進(jìn)行縮放或者旋轉(zhuǎn),松開按鈕后圖像復(fù)原。

    提示:即縮放又旋轉(zhuǎn)這個(gè)例子,并沒有使用變形矩陣,而是用了四步簡(jiǎn)單變形復(fù)合而成。效果如下:

    你的瀏覽器不支持 <canvas>標(biāo)簽,請(qǐng)使用 Chrome 瀏覽器 或者 FireFox 瀏覽器
    移動(dòng)——在圖像上按住鼠標(biāo)并移動(dòng)
    基準(zhǔn)點(diǎn)縮放——在圖像某點(diǎn)處按住鼠標(biāo)
    基準(zhǔn)點(diǎn)旋轉(zhuǎn)——在圖像某點(diǎn)處按住鼠標(biāo)
    基準(zhǔn)點(diǎn)縮放同時(shí)旋轉(zhuǎn)——在圖像某點(diǎn)處按住鼠標(biāo)

     

    四、組合

    所謂組合就是一個(gè)圖形繪制在另一個(gè)圖形之上,會(huì)出現(xiàn)什么效果。默認(rèn)的情況下是上面的圖形覆蓋了下面的圖形,稱之為 source-over 。

    上下文對(duì)象總共十二中組合類型,屬性 globalCompositeOperation 被用來設(shè)置組合類型,如下:

    globalCompositeOperation = type

    type 是下面 12 種字符串值之一:

    注意:上面所有例子中,藍(lán)色方塊是先繪制的,即“已有的 canvas 內(nèi)容”,紅色圓形是后面繪制,即“新圖形”。













     

    五、裁剪路徑

    在第一篇文章中我們就介紹了上下文對(duì)象的兩大類繪制方法,即繪制線條的 stroke 系列方法和填充區(qū)域的 fill 系列方法,其實(shí),上下文對(duì)象還有一類繪制方法叫做裁剪 clip

    什么是裁剪呢?打個(gè)不恰當(dāng)?shù)谋确桨桑阌靡粔K布把電視機(jī)屏幕遮住了,這時(shí)候電視機(jī)屏幕上的任何變化你都看不見了。

    但是,如果你布上裁剪出一塊區(qū)域,那么至少這塊區(qū)域里的屏幕變化你能看見。

    當(dāng)然裁剪區(qū)域之外的屏幕也在不停地變化(即也在重新繪制),只是你看不見罷了。這就是所謂的裁剪,平常在處理圖像時(shí)經(jīng)常會(huì)遇到這種需求。

    那么什么又是裁剪路徑呢?上面說要在布上裁剪出一塊區(qū)域,這塊區(qū)域是怎么來的呢?

    這塊區(qū)域是在裁剪動(dòng)作 clip 之前,由繪圖路徑設(shè)定的,他可以是方形、圓形、五星形和其他任何可以繪制的輪廓形狀。

    所以,裁剪路徑其實(shí)就是繪圖路徑,只不過這個(gè)路徑不是拿來繪圖的,而是設(shè)定顯示區(qū)域和遮擋區(qū)域的一個(gè)分界線。

    如果你不明白什么是繪圖路徑,在前的文章 HTML5邊玩邊學(xué)(2):基礎(chǔ)繪圖 中有介紹。

    下面的例子用了兩種方法進(jìn)行裁剪。第一種方法顯示一來回移動(dòng)的圓形裁剪區(qū)域,大體流程如下:

    1、清空畫布

    2、改變圓心位置

    3、在新的圓心位置處設(shè)置一個(gè)圓形的裁剪區(qū)域

    4、在畫布上繪制美女圖像

    由于我們不停地在新位置處設(shè)定裁剪區(qū)域,我們就能看見裁剪區(qū)域在移動(dòng),而裁剪區(qū)域之外的圖像并沒有顯示出來

     

    我們用 clip 方法設(shè)置裁剪區(qū)域,之后繪制的圖形只能顯示裁剪區(qū)域內(nèi)的一部分,而裁剪區(qū)域之外總是顯示畫布的背景色。

    假如并不想完全遮擋裁剪區(qū)域之外的圖像,比如我們想讓裁剪區(qū)域之內(nèi)的圖像完全顯示出來,但是裁剪區(qū)域之外的圖像以半透明的方式顯示出來,該怎么做呢?

    這就要用到我們上面說的的組合知識(shí)了。第二中方法顯示半透明的遮擋,大體思路如下:

    1、清空畫布

    2、將畫布的所有區(qū)域用一種半透明的顏色填充,這里我用的是灰色,透明度0.9

    3、改變圓心位置

    4、在新的圓心位置處以 XOR 方式繪制圓,這樣和圓形重疊的部分將被擦除掉
    這時(shí)候我們得到的圖形效果是一個(gè)半透明的畫布,上面有一塊完全透明的圓形區(qū)域

    5、 在第 4 步的基礎(chǔ)上,以 destination-over 方式繪制美女圖像,這時(shí)候美女圖像將會(huì)出現(xiàn)在第 4 步圖形效果的下方,想象一下,正好是我們想要的效果吧?!

    效果如下:

    你的瀏覽器不支持 <canvas>標(biāo)簽,請(qǐng)使用 Chrome 瀏覽器 或者 FireFox 瀏覽器

     

    所有程序的代碼:

    代碼
    <canvas id="canvas1" width="250" height="300" 
        onmousedown
    ="trans.transform(event);"  
        onmouseup
    ="trans.init(event);" 
        onmousemove
    ="trans.translate(event);" 
        style
    ="background-color:black">
        你的瀏覽器不支持 
    &lt;canvas&gt;標(biāo)簽,請(qǐng)使用 Chrome 瀏覽器 或者 FireFox 瀏覽器
    </canvas><br/>
    <input type="radio" name="r" id="r1" checked="checked">移動(dòng)——在圖像上按住鼠標(biāo)并移動(dòng)<br />
    <input type="radio" name="r" id="r2">基準(zhǔn)點(diǎn)縮放——在圖像某點(diǎn)處按住鼠標(biāo)<br />
    <input type="radio" name="r"  id="r3">基準(zhǔn)點(diǎn)旋轉(zhuǎn)——在圖像某點(diǎn)處按住鼠標(biāo)<br />
    <input type="radio" name="r"  id="r4">基準(zhǔn)點(diǎn)縮放同時(shí)旋轉(zhuǎn)——在圖像某點(diǎn)處按住鼠標(biāo)<br />

    <canvas id="canvas3" width="250" height="300" style="background-color:black">
        你的瀏覽器不支持 
    &lt;canvas&gt;標(biāo)簽,請(qǐng)使用 Chrome 瀏覽器 或者 FireFox 瀏覽器
    </canvas><br/>
    <input type="button" onclick="move(1);" value="移動(dòng)裁剪區(qū)域">
    <input type="button" onclick="move(2);" value="移動(dòng)蒙版">
    <input type="button" onclick="stop();" value="停止移動(dòng)"><br />

            
    <div>
                
    <table>
                    
    <tr>
                        
    <td><canvas id="tut0" width="125" height="125"></canvas><br/><label id="lab0"></label></td>
                    
    <td><canvas id="tut1" width="125" height="125"></canvas><br/><label id="lab1"></label></td>
                    
    <td><canvas id="tut2" width="125" height="125"></canvas><br/><label id="lab2"></label></td>
                    
    <td><canvas id="tut3" width="125" height="125"></canvas><br/><label id="lab3"></label></td>
                    
    </tr>
                    
    <tr>
                        
    <td><canvas id="tut4" width="125" height="125"></canvas><br/><label id="lab4"></label></td>
                    
    <td><canvas id="tut5" width="125" height="125"></canvas><br/><label id="lab5"></label></td>
                    
    <td><canvas id="tut6" width="125" height="125"></canvas><br/><label id="lab6"></label></td>
                    
    <td><canvas id="tut7" width="125" height="125"></canvas><br/><label id="lab7"></label></td>
                    
    </tr>
                    
    <tr>
                        
    <td><canvas id="tut8" width="125" height="125"></canvas><br/><label id="lab8"></label></td>
                    
    <td><canvas id="tut9" width="125" height="125"></canvas><br/><label id="lab9"></label></td>
                    
    <td><canvas id="tut10" width="125" height="125"></canvas><br/><label id="lab10"></label></td>
                    
    <td><canvas id="tut11" width="125" height="125"></canvas><br/><label id="lab11"></label></td>
                    
    </tr>
                
    </table>
            
    </div>


    <script type="text/javascript">
        
    //美女圖的 Base64 編碼
        IMG_SRC='data:image/gif;base64,/9j/4QDfRXhpZgAASUkqAAgAAAAFABIBAwA......';//省略四十字節(jié)

        
    //==========================================
        
    //基準(zhǔn)點(diǎn)變形類
        
    //==========================================
        function Transform(){
            
    //獲取畫布對(duì)象
            this.ctx = document.getElementById("canvas1").getContext("2d");
            
    //創(chuàng)建圖像對(duì)象
            this.img=new Image();
            
    //指定圖像源
            this.img.src=IMG_SRC;
            
    this.interval = null;
            
    //鼠標(biāo)按鈕狀態(tài)
            this.pressed=false;
            
    this.init();
        }
        
        
    //初始化圖形
        Transform.prototype.init=function(){
            
    //鼠標(biāo)按鈕狀態(tài)
            this.pressed=false;
            
    //停止計(jì)時(shí)器
            if(this.interval) clearInterval(this.interval);
            
    //變化值
            this.delta = 0.06;
            
    //清空
            this.ctx.clearRect(0,0,250,300);
            
    //重繪
            this.paint();
        }
        
        
    //繪制圖像
        Transform.prototype.paint=function(){
            var that
    =this;
            var img
    =this.img
            
    if(img.complete)
                that.ctx.drawImage(img,
    0,0);
            
    else 
                var interval 
    = setInterval(function(){
                    
    if(img.complete){
                        that.ctx.drawImage(img,
    0,0);
                        clearInterval(interval);
                    }
                },
    300);
        }
        
        
    //鼠標(biāo)按鈕按下后,開始變形
        Transform.prototype.transform = function(){
            
    //獲取基準(zhǔn)點(diǎn)
            this.dx=event.offsetX;
            
    this.dy=event.offsetY;
            
    //獲取基準(zhǔn)點(diǎn)
            this.startx=event.offsetX;
            
    this.starty=event.offsetY;
            
    //初始縮放比例
            this.sc=1;
            
    //初旋轉(zhuǎn)角度
            this.angle=0;
            
            var that
    =this;
            
    if(document.getElementById("r1").checked)
                
    //鼠標(biāo)按鈕狀態(tài)
                this.pressed=true;
            
    else if(document.getElementById("r2").checked)
                
    this.interval = setInterval(function(){that.scale()},50);
            
    else if((document.getElementById("r3").checked))
                
    this.interval = setInterval(function(){that.rotate()},50);
            
    else 
                
    this.interval = setInterval(function(){that.scaleAndRotate()},50);
        }
        
        
    //移動(dòng)
        Transform.prototype.translate = function(){
            
    this.ddx=event.offsetX-this.startx;
            
    this.ddy=event.offsetY-this.starty;
            
    if(this.pressed){
                
    //清空
                this.ctx.clearRect(0,0,250,300);
                
    //保存狀態(tài)
                this.ctx.save();
                
    //平移
                this.ctx.translate(this.ddx,this.ddy);
                
    //重繪
                this.paint();
                
    //繪制基準(zhǔn)點(diǎn)
                this.ctx.fillStyle="red";
                
    this.ctx.fillRect(this.dx-5,this.dy-5,10,10);
                
    //恢復(fù)狀態(tài)
                this.ctx.restore();
            }
        }

        
    //縮放變形
        Transform.prototype.scale = function(){
            
    //清空
            this.ctx.clearRect(0,0,250,300);
            
    //改變縮放比例
            this.sc=this.sc - this.delta;
            
    if(this.sc<0.2 || this.sc>2
                
    this.delta = -this.delta;
            
    //保存狀態(tài)
            this.ctx.save();
            
    //以 (dx,dy) 為基準(zhǔn)點(diǎn)進(jìn)行 (sx,sy)比例縮放:transform(sx, 0, 0, sy, dx(1-sx), dy(1-sy))
            this.ctx.transform(this.sc, 00this.sc, this.dx*(1-this.sc), this.dy*(1-this.sc))
            
    //用新的變形矩陣重繪
            this.paint();
            
    //繪制基準(zhǔn)點(diǎn)
            this.ctx.fillStyle="red";
            
    this.ctx.fillRect(this.dx-5,this.dy-5,10,10);
            
    //恢復(fù)狀態(tài)
            this.ctx.restore();
        }
        
        
    //旋轉(zhuǎn)變形
        Transform.prototype.rotate = function(){
            
    //清空
            this.ctx.clearRect(0,0,250,300);
            
    //改變縮放比例
            var PI = Math.PI;
            
    this.angle=this.angle + PI/60;
            
    //保存狀態(tài)
            this.ctx.save();
            
    //以 (dx,dy) 為基準(zhǔn)點(diǎn)旋轉(zhuǎn)角度 A:transform(cosA, sinA, -sinA, cosA, dx(1-cosA) + dysinA, dy(1-cosA) - dxsinA)
            this.ctx.transform(Math.cos(this.angle), Math.sin(this.angle), 
                    
    -Math.sin(this.angle), Math.cos(this.angle), 
                    
    this.dx*(1-Math.cos(this.angle)) + this.dy*Math.sin(this.angle), 
                    
    this.dy*(1-Math.cos(this.angle)) - this.dx*Math.sin(this.angle))
            
    //用新的變形矩陣重繪
            this.paint();
            
    //繪制基準(zhǔn)點(diǎn)
            this.ctx.fillStyle="red";
            
    this.ctx.fillRect(this.dx-5,this.dy-5,10,10);
            
    //恢復(fù)狀態(tài)
            this.ctx.restore();
        }
        
        
    //即縮放又旋轉(zhuǎn)變形,沒有使用變形矩陣
        Transform.prototype.scaleAndRotate = function(){
            
    //清空
            this.ctx.clearRect(0,0,250,300);
            
    //改變縮放比例
            this.sc=this.sc - this.delta;
            
    if(this.sc<0.2 || this.sc>2
                
    this.delta = -this.delta;
            var PI 
    = Math.PI;
            
    this.angle=this.angle + PI/60;
            
    //保存狀態(tài)
            this.ctx.save();
            
    //先移動(dòng)原點(diǎn)到基點(diǎn)
            this.ctx.translate(this.dx,this.dy);
            
    this.ctx.scale(this.sc,this.sc);
            
    this.ctx.rotate(this.angle);
            
    this.ctx.translate(-this.dx,-this.dy);
            
    //用新的變形矩陣重繪
            this.paint();
            
    //繪制基準(zhǔn)點(diǎn)
            this.ctx.fillStyle="red";
            
    this.ctx.fillRect(this.dx-5,this.dy-5,10,10);
            
    //恢復(fù)狀態(tài)
            this.ctx.restore();
        }
        
        var trans 
    = new Transform();
        
        
    //==========================================
        function Clip(){
            var canvas 
    = document.getElementById("canvas3");
            
    this.ctx = canvas.getContext("2d");
            
    this.img=new Image();
            
    this.img.src=IMG_SRC;
            
    //移動(dòng)方向
            this.delta=[3,3];
            
    //起始點(diǎn)
            this.pos_x = 225;
            
    this.pos_y = 120;
            
    //半徑
            this.radius = 40;
            
    //畫布的長(zhǎng)和寬
            this.w = parseInt(canvas.getAttribute("width"));
            
    this.h = parseInt(canvas.getAttribute("height"));
        }
        
        Clip.prototype.draw1
    =function(){
            
    //碰撞檢測(cè)
            if (this.pos_x < this.radius) {
                
    this.delta[0= Math.random() % 4 + 5;
            } 
    else if (this.pos_x > this.w - this.radius) {
                
    this.delta[0= -(Math.random() % 4 + 5);
            }
            
    if (this.pos_y < this.radius) {
                
    this.delta[1= Math.random() % 4 + 5;
            } 
    else if (this.pos_y > this.h - this.radius) {
                
    this.delta[1= -(Math.random() % 4 + 5);
            }
            
    this.pos_x += this.delta[0];
            
    this.pos_y += this.delta[1];

            
    this.ctx.clearRect(00this.w, this.h);
            
    //保存狀態(tài)
            this.ctx.save()
            
    //移動(dòng)變形
            this.ctx.translate(this.pos_x,this.pos_y);
            
    //設(shè)置裁剪區(qū)域
            this.ctx.beginPath();
            
    this.ctx.arc(0 ,0,this.radius,0,Math.PI*2,true);
            
    this.ctx.clip();         
            
    // 將圖片畫到畫布上
            this.ctx.drawImage(this.img, -this.pos_x, -this.pos_y,this.w, this.h);
            
    //恢復(fù)狀態(tài)
            this.ctx.restore();
        }
        
        Clip.prototype.draw2
    =function(){
            
    //碰撞檢測(cè)
            if (this.pos_x < this.radius) {
                
    this.delta[0= Math.random() % 4 + 5;
            } 
    else if (this.pos_x > this.w - this.radius) {
                
    this.delta[0= -(Math.random() % 4 + 5);
            }
            
    if (this.pos_y < this.radius) {
                
    this.delta[1= Math.random() % 4 + 5;
            } 
    else if (this.pos_y > this.h - this.radius) {
                
    this.delta[1= -(Math.random() % 4 + 5);
            }
            
    this.pos_x += this.delta[0];
            
    this.pos_y += this.delta[1];

            
    this.ctx.clearRect(00this.w, this.h);
            
    //繪制灰色的半透明蒙版
            this.ctx.fillStyle="rgba(125,125,125,0.9)"
            
    this.ctx.fillRect(00this.w, this.h);
            
    //保存狀態(tài)
            this.ctx.save()
            
    //移動(dòng)坐標(biāo)
            this.ctx.translate(this.pos_x,this.pos_y);
            
    //裁剪透明的圓形區(qū)域
            this.ctx.globalCompositeOperation = "xor";   
            
    this.ctx.fillStyle="white"
            
    this.ctx.beginPath();
            
    this.ctx.arc(0 ,0,this.radius,0,Math.PI*2,true);
            
    this.ctx.fill();       
            
    // 將圖片畫到蒙版的下面,即只露出透明區(qū)域
            this.ctx.globalCompositeOperation = "destination-over";   
            
    this.ctx.drawImage(this.img, -this.pos_x, -this.pos_y,this.w, this.h);
            
    //恢復(fù)狀態(tài)
            this.ctx.restore();
        }

        var cl
    =new Clip();
        cl.interval
    =null;
        
        function move(id){      
            
    if(cl.interval)
                clearInterval(cl.interval)
            
    if(id==1){
                cl.ctx.clearRect(
    00450300);    
                cl.interval
    =setInterval(function(){cl.draw1()},20);
            }
            
    else{
                cl.ctx.clearRect(
    00450300);    
                cl.interval
    =setInterval(function(){cl.draw2()},20);
            }
        }

        function stop(){
            clearInterval(cl.interval)
        }
        
        var compositeTypes 
    = [
            
    'source-over','source-in','source-out','source-atop',
            
    'destination-over','destination-in','destination-out','destination-atop',
            
    'lighter','darker','copy','xor'
        ];
        function drawComp(){
            
    for (i=0;i<compositeTypes.length;i++){
                var label 
    = document.createTextNode(compositeTypes[i]);
                document.getElementById(
    'lab'+i).appendChild(label);
                var ctx 
    = document.getElementById('tut'+i).getContext('2d');

                
    // draw rectangle
                ctx.fillStyle = "#09f";
                ctx.fillRect(
    15,15,70,70);

                
    // set composite property
                ctx.globalCompositeOperation = compositeTypes[i];

                
    // draw circle
                ctx.fillStyle = "#f30";
                ctx.beginPath();
                ctx.arc(
    75,75,35,0,Math.PI*2,true);
                ctx.fill();
            }
        }
        drawComp();
    </script>

     

     

     

    //==========================================

    posted on 2010-10-05 12:34 左洸 閱讀(2855) 評(píng)論(4)  編輯  收藏 所屬分類: HTML5

    FeedBack:
    # re: HTML5邊玩邊學(xué)(6):汽車人,變形......
    2010-10-05 12:37 | 左洸
    沙發(fā)提示:
    可能需要 Google Chrome 瀏覽器才能看到全部正確的效果。

    使用 Firefox 瀏覽器,第一個(gè)例子的無法運(yùn)行,后面的可以  回復(fù)  更多評(píng)論
      
    # re: HTML5邊玩邊學(xué)(6):汽車人,變形......
    2010-10-05 16:16 | syg
    html5有很不錯(cuò)的體驗(yàn),但把ie踢出局就不明智了  回復(fù)  更多評(píng)論
      
    # re: HTML5邊玩邊學(xué)(6):汽車人,變形......
    2010-10-05 18:17 | 別玩HTML5了,閑的蛋疼
    現(xiàn)在搞HTML5分明是蛋疼,2030年你能放心的把HTML5用到產(chǎn)品里就不錯(cuò)了,IE6還不敢拋棄呢還意淫HTML5,你敢檢測(cè)出來IE6后alert(“爺就是不支持IE6,咋滴?”)嗎?????? IE6后是IE7,IE7后面是IE8,IE9還不知道咋樣,現(xiàn)在你就玩HTML5?閑的?  回復(fù)  更多評(píng)論
      
    # re: HTML5邊玩邊學(xué)(6):汽車人,變形......
    2012-04-26 20:50 | joel
    支持樓主,上面講的很不錯(cuò)!還希望有機(jī)會(huì)能多多討教  回復(fù)  更多評(píng)論
      
    主站蜘蛛池模板: 中文字幕亚洲一区二区va在线| 国产亚洲美女精品久久| 国产精品成人免费福利| 久久精品国产亚洲AV高清热| 日本在线免费观看| 亚洲色WWW成人永久网址| 伊人久久大香线蕉免费视频| 国产av无码专区亚洲av果冻传媒| 亚欧国产一级在线免费| 国产亚洲日韩一区二区三区| 精品国产免费人成网站| 亚洲乱码精品久久久久..| 99麻豆久久久国产精品免费| 亚洲精品无码专区久久久| 中文成人久久久久影院免费观看| 最新亚洲成av人免费看| 在线观看人成视频免费无遮挡| 亚洲成Av人片乱码色午夜| 久久国产精品成人免费| 18亚洲男同志videos网站| 亚洲国产精品免费在线观看| 亚洲国产成人精品电影| 午夜宅男在线永久免费观看网| 亚洲国产视频久久| 免费看少妇作爱视频| 亚洲avav天堂av在线网毛片| 免费国产一级特黄久久| 四虎一区二区成人免费影院网址| 国产成人亚洲综合无码| 中文字幕免费观看全部电影| 亚洲AV无码成人专区片在线观看| 免费A级毛片无码专区| 亚洲第一二三四区| 国语成本人片免费av无码| 亚洲av成人一区二区三区观看在线| 亚洲成?v人片天堂网无码| 国产精品偷伦视频免费观看了| 亚洲国产三级在线观看| 97久久免费视频| 亚洲一区二区三区写真| 国产一区二区三区在线观看免费|