搜尋
首頁web前端H5教程用HTML5 實現橡皮擦的塗抹效果的教學_html5教學技巧

最近專案剛好用到這種效果,也就是有點像刮刮卡一樣,在行動裝置上,把某張圖片刮掉顯示出另一張圖片。效果圖如下:
2015511163305472.png (974×840)

DEMO請戳右:DEMO 
這種在網路上還是挺常見的,本來就想直接上網找個demo套用下他的方法就行了,套用了才發現,在android上卡出翔了,因為客戶要求,在android不要求特別流暢,至少要能玩,但是網上找的那個demo實在太卡,根本就是沒辦法玩的情況。於是就想自己寫一個算了,本文也就權當記錄研究過程。

  這種刮圖的效果,首先想到就是用HTML5的canvas來實現,而canvas的API中,可以清除像素的就是clearRect方法,但是clearRect方法的清除區域矩形​​,畢竟大部分人的習慣中的橡皮擦都是圓形的,所以就引入了剪輯區域這個強大的功能,也就是clip方法。用法很簡單: 

XML/HTML Code複製內容到剪貼簿
  1. ctx.save()   
  2. ctx.beginPath()   
  3. ctx.arc(x2,y2,a,0,2*Math.PI);   
  4. ctx.clip()   
  5. ctx.clearRect(0,0,canvas.width,canvas.height);   
  6. ctx.restore();   

  上面那段程式碼就實現了圓形區域的擦除,也就是先實作一個圓形路徑,然後把這個路徑當作剪輯區域,再清除像素就行了。有個注意點就是需要先保存繪圖環境,清除完像素後要重置繪圖環境,如果不重置的話以後的繪圖都是會被限制在那個剪輯區域中。

  擦除效果有了,現在就是寫滑鼠移動擦除的效果了,下面我均用滑鼠來描述,因為行動端也差不多,就是把mousedown換成touchstart,mousemove換成touchmove,mouseup換成touchend 、以及取得座標點由e.clientX換成e.targetTouches[0].pageX而已。

  實現滑鼠移動擦除,剛開始就是想到滑鼠移動時在觸發的mousemove事件中對滑鼠所在位置進行圓形區域擦除,寫出來後發現,當滑鼠移動速度很快的時候,擦除的區域就不連貫了,就會出現下面這種效果,這顯然不是我們想要的橡皮擦擦除效果。
2015511163949198.jpg (1103×693)

既然所有點不連貫,那接下來要做的事就是把這些點連貫起來,如果是實現畫圖功能的話,就可以直接通過lineTo把兩點之間連接起來再繪製,但是擦除效果中的剪輯區域要求要是閉合路徑,如果是單純的把兩點連起來就無法形成剪輯區域了。然後我就想到用計算的方法,算出兩個擦除區域中的矩形四個端點座標來實現,也就是下圖中的紅色矩形:
2015511164105508.png (343×129)

計算方法也很簡單,因為可以知道兩個剪輯區域連線兩個端點的座標,又知道我們要多寬的線條,矩形的四個端點座標就變得容易求了,所以就有了下面的程式碼:
XML/HTML Code複製內容到剪貼簿

  1. var aasin = a*Math.sin(Math.atan((y2-y1)/(x2-. x1)));   
  2. var aacos = a*Math.cos(Math.atan((y2-y1)/(x2-x1)) )   
  3. var x3 = x1 asin;  x1
  4. asin;   var y3 = y1
  5. -acos;   var x4 = x1
  6. -asin;   var y4 = y1
  7. acos;  
  8. y1 acos;   var x5 = 
  9. x2 asin;  x2 asin;   var 
  10. y5
  11.  = y2-acos;  -acos;  
  12. var x6 = x2-asin;  
var 
y6 = y2 acos;

  x1、y1和x2、y2就是兩個端點,從而求出了四個端點的座標。這樣一來,剪輯區域就是圈加矩形,程式碼組織起來就是:
XML/HTML Code複製內容到剪貼簿

  1. var hastouch = "ontouchstart" .為行動裝置  
  2.     tapstart = hastouch?"touch     
  3. tapmove = hastouch?"touchmove     tapend
  4.  = hastouch?"touchend":?"touchend"    canvas.addEventListener(tapstart , function(e){   
  5.     e.preventDefault();   
  6.        
  7.     
  8. x1 = 
  9. hastouch?e.. ;        y1 = 
  10. hastouch?e.. ;              //滑鼠第一次點下的時候擦除一個圓形區域,同時記錄第一個座標點   
  11.     ctx.save()   
  12.     ctx.beginPath()   
  13.     ctx.arc(x1,y1,a,0,2*Math.PI);   
  14.     ctx.clip()   
  15.     ctx.clearRect(0,0,canvas.width,canvas.height);   
  16.     ctx.restore();   
  17.        
  18.     canvas.addEventListener(tapmove , tapmoveHandler);   
  19.     canvas.addEventListener(tapend , function(){   
  20.         canvas.removeEventListener(tapmove , tapmoveHandler);   
  21.     });   
  22.   //老鼠移動時觸發此事件   
  23.     function tapmoveHandler(e){   
  24.         e.preventDefault()   
  25.         x2 = hastouchLe. ;   
  26.         y2 = hastouch?e. ;   
  27.            
  28.     //取得兩個點之間的剪輯區域四個端點   
  29.         var aasin = a*Math.sin(Math.atan(y = a*Math.sin(Math. );   
  30.         var aacos = a*Math.cos(Math.atan(y
  31.  = a*Math.cos(Math.at12x2x )   
  32.         var x3 =         var 
  33. y3 = y1 = y1        var 
  34. x4 = x1 = x1        var 
  35. y4 =         var x5 = 
  36.         var y5 = y2 = 
  37.         var 
  38. x6 = x2 = x2
  39.         var 
  40. y6 = 
  41.                 //保證線的連貫,所以在長方形一端畫圓   
  42.         ctx.save()            ctx.beginPath()            ctx.arc(x2,y2,a,0,2*Math.PI);   
  43.         ctx.clip()   
  44.         ctx.clearRect(0,0,canvas.width,canvas.height);   
  45.         ctx.restore();   
  46.        
  47.     //清除矩形剪輯區域裡的像素   
  48.         ctx.save()   
  49.         ctx.beginPath()   
  50.         ctx.moveTo(x3,y3);   
  51.         ctx.lineTo(x5,y5);   
  52.         ctx.lineTo(x6,y6);   
  53.         ctx.lineTo(x4,y4);   
  54.         ctx.closePath();   
  55.         ctx.clip()   
  56.         ctx.clearRect(0,0,canvas.width,canvas.height);   
  57.         ctx.restore();   
  58.            
  59.     //記錄最後座標   
  60.         x1 = x2;
  61.         
  62. y1 = y2;     }   
  63. })  
  64.   如此一來,滑鼠擦除的效果就實現了,不過還有一個要實現的點,就是大部分擦除的效果,當你擦了一定數量的像素後,就會自動把所有圖片內容呈現出來,這個效果,我是用imgData來實現的。程式碼如下:
複製程式碼


XML/HTML Code

複製內容到剪貼簿
var 
  1. imgData = ctx.getImmmageData(w,0cancanvas. height);    var 
  2. dd
  3.  = 0;   ;   
  4. ;   
  5. ;    for(var x=0;x
  6. 0
  7. ;ximgData.width;x =1){        for(var y=0
  8. ;
  9. 0; >imgData.height;y =1){   
  10.         var i = (y*imgData.width   x)*4  = (y*imgData.width   x)*4  = (y*imgData.
  11.         if(imgData.data[i 3] 
  12. >
  13.  0){   
  14.  0){   
  15.             dd   
  16.         }   
  17.     }    }   
  18. if(dd/(imgData.width*imgData.height)0.4){   ){   
  19.     
canvas.className
 = "noOp"; }  

  取得到imgData,對imgData裡的像素進行遍歷,然後再對imgData的data數組裡的rgba中的alpha進行分析,也就是分析透明度,如果像素被擦除了,那麼透明度就是0了,也就是把目前畫布中透明度不為0的像素的數量跟畫布總像素數進行比較,如果透明度不為0 的像素數比例低於40%,那表示當前畫布上就以後有百分六十以上的區域被擦除了,就可以自動呈現圖片了。

  這裡注意,我是把檢查像素這段程式碼方法mouseup事件裡面的,因為這個計算量相對來說還是不小,如果用戶狂點滑鼠,就會狂觸發mouseup事件,也就是會瘋狂的觸發那個循環計算像素,計算量大到阻塞進程,導致界面卡住的情況,緩解辦法如下:加個timeout,延遲執行像素計算,而在每一次點擊的時候再清除timeout,也就是如果用戶點擊很快,這個計算也就觸發不了了,還有一個提升的辦法就是抽樣檢查,我上面的寫法是逐個像素檢查,逐個像素檢查的話像素量太大,肯定會卡的,所以可以採用抽樣檢查,比如每隔30個像素檢查一次,修改後的程式碼如下:
複製程式碼

XML/HTML Code複製內容到剪貼簿
  1. timeout = setTimeout(function(){   
  2.     var imgData = ctx
  3.     var dd = 0;  >0
  4. ;   ;     for(var x=0;x0; >imgData.width
  5. ;x =30){            for(var y=0=0 imgData.height
  6. ;y =30){   
  7.             var i
  8.  = (y*imgData.width  
  9.             if(imgData.data[i 3] >0){   >
  10. 0){   
  11.                 dd   
  12.             }   
  13.         }   
  14.     }        if(dd/(imgData.width*imgData.height/900)0.4
  15. 0.4
  16.         
  17. canvas.className
  18.  = 
  19.     }   
},100)   

  這樣就可以較大限度的防止用戶狂點擊了,如果有其他更好的檢查方法歡迎給出意見,謝謝。

  到了這一步就都寫完了,然後就是測試的時候了,結果並不樂觀,在android上還是卡啊卡啊,所以又得另想辦法,最終發現了繪圖環境中的globalCompositeOperation這個屬性,這個屬性的預設值是source-over,也就是,當你在已有像素上進行繪圖時會疊加,但是還有一個屬性是destination-out,官方解釋就是:在來源影像外顯示目標影像。只有來源影像外的目標影像部分才會被顯示,來源影像是透明的。好像不太好理解,但是其實自己測試一下就會發現很簡單,也就是在已有像素的基礎上進行繪圖時,你繪製的區域裡的已有像素都會被置為透明,直接看張圖更容易理解:
2015511164219714.jpg (553×390)

globalCompositeOperation屬性效果圖解。
有了這個屬性後,就意味著不需要用到clip,也就不需要用sin、cos什麼的計算剪輯區域,直接用條粗線就行了,這樣一來就能夠很大限度的降低了運算量,同時減少了繪圖環境API的調用,效能提升了,在android上運行應該也會流暢很多,以下是修改後的程式碼:


XML/HTML Code複製內容到剪貼簿
  1. //透過修改globalCompositeOperation來達到擦除的效果   
  2. function tapClip(){   
  3.     var hastouch = "ontouchstart""ontouchstart"
  4.         tapstart = hastouch = 
  5. hastouch =          tapmove = 
  6. hastouch
  7.  = hastouch        tapend = 
  8. hastouch
  9.  = hastouch
  10.        
  11.     canvas.addEventListener(tapstart , function(e){   
  12.      clearTimeout(timeout)   
  13.         e.preventDefault();   
  14.                     x1 = 
  15. hastouch
  16. ;            y1 = hastouch
  17. ?e. ;   
  18.                     ctx.lineCap = "round"
  19.  = 
  20. "round" = "round" = "round" = "round"
  21.  = 
  22. "r.         ctx.lineJoin = 
  23.         ctx.lineWidth = a        ctx.globalCompositeOperation
  24.  =            
  25.         ctx.save();   
  26.         ctx.beginPath()   
  27.         ctx.arc(x1,y1,1,0,2*Math.PI);   
  28.         ctx.fill();   
  29.         ctx.restore();   
  30.            
  31.         canvas.addEventListener(tapmove , tapmoveHandler);   
  32.         canvas.addEventListener(tapend , function(){   
  33.             canvas.removeEventListener(tapmove , tapmoveHandler);   
  34.                
  35.        timeout = setTimeout = 
  36. setTimeout = setTimeout             var imgData = ctx             var 
  37. dd = 0 = 00;   
  38.             for(var x=0;ximgData.width;x =30){   
  39.                 for(var y=y= 🎜> imgData.height;y =30){   
  40.                       var 
  41. ii
  42.                       if(imgData.data[i 3]                         dd   
  43.                     }   
  44.                 }   
  45.             }   
  46.             if(dd/(imgData.width*imgData.height/900)
  47. 0.                 canvas.className = canvas.className
  48.  =    
  49.             }    100)   
  50.         });   
  51.         函數tapmoveHandler(e){   
  52.             e.preventDefault()   
  53.             x2 =              
  54. y2 = hastouch =                 
  55.             ctx.save();   
  56.             ctx.moveTo(x1,y1);   
  57.             ctx.lineTo(x2,y2);   
  58.             ctx.中風();   
  59.             ctx.restore()   
  60.                
  61.             
  62. x1
  63.  = x2 = x2;   
  64.             y1 = y2 = y2
  65. ;   
  66.         }   
  67.     })   
  68. }   

恐怖那部分代码就这么一点,非常虚拟画图功能,直接设置线属性后通过线进行不平等的线条,只要事前把globalCompositeOperation设定成destination-out,你所进行的一切的一切,都变成了有了效果。鼠标滑动触发的事件里面的代码也少了很多,绘图对象的调用次数减少了,计算也减少了,性能提升大大滴。

好的程式碼以後就立即用自己的android機子測試一下,果然如此,跟上一個相比,流暢了很多,至少達到了客戶要求的能玩的地步了。 位址原始碼:https://github.com/whxaxes/canvas-test/blob/gh-pages/src/Funny-demo/clip/clip.html

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
H5和HTML5之間的連接:相似性和差異H5和HTML5之間的連接:相似性和差異Apr 24, 2025 am 12:01 AM

H5和HTML5是不同的概念:HTML5是HTML的一個版本,包含新元素和API;H5是基於HTML5的移動應用開發框架。 HTML5通過瀏覽器解析和渲染代碼,H5應用則需要容器運行並通過JavaScript與原生代碼交互。

H5代碼的基礎:密鑰元素及其目的H5代碼的基礎:密鑰元素及其目的Apr 23, 2025 am 12:09 AM

HTML5的關鍵元素包括、、、、、等,用於構建現代網頁。 1.定義頭部內容,2.用於導航鏈接,3.表示獨立文章內容,4.組織頁面內容,5.展示側邊欄內容,6.定義頁腳,這些元素增強了網頁的結構和功能性。

HTML5和H5:了解常見用法HTML5和H5:了解常見用法Apr 22, 2025 am 12:01 AM

HTML5和H5沒有區別,H5是HTML5的簡稱。 1.HTML5是HTML的第五個版本,增強了網頁的多媒體和交互功能。 2.H5常用於指代基於HTML5的移動網頁或應用,適用於各種移動設備。

HTML5:現代網絡的基礎(H5)HTML5:現代網絡的基礎(H5)Apr 21, 2025 am 12:05 AM

HTML5是超文本標記語言的最新版本,由W3C標準化。 HTML5引入了新的語義化標籤、多媒體支持和表單增強,提升了網頁結構、用戶體驗和SEO效果。 HTML5引入了新的語義化標籤,如、、、等,使網頁結構更清晰,SEO效果更好。 HTML5支持多媒體元素和,無需第三方插件,提升了用戶體驗和加載速度。 HTML5增強了表單功能,引入了新的輸入類型如、等,提高了用戶體驗和表單驗證效率。

H5代碼:編寫清潔有效的HTML5H5代碼:編寫清潔有效的HTML5Apr 20, 2025 am 12:06 AM

如何寫出乾淨高效的HTML5代碼?答案是通過語義化標籤、結構化代碼、性能優化和避免常見錯誤。 1.使用語義化標籤如、等,提升代碼可讀性和SEO效果。 2.保持代碼結構化和可讀性,使用適當縮進和註釋。 3.優化性能,通過減少不必要的標籤、使用CDN和壓縮代碼。 4.避免常見錯誤,如標籤未閉合,確保代碼有效性。

H5:如何增強網絡上的用戶體驗H5:如何增強網絡上的用戶體驗Apr 19, 2025 am 12:08 AM

H5通過多媒體支持、離線存儲和性能優化提升網頁用戶體驗。 1)多媒體支持:H5的和元素簡化開發,提升用戶體驗。 2)離線存儲:WebStorage和IndexedDB允許離線使用,提升體驗。 3)性能優化:WebWorkers和元素優化性能,減少帶寬消耗。

解構H5代碼:標籤,元素和屬性解構H5代碼:標籤,元素和屬性Apr 18, 2025 am 12:06 AM

HTML5代碼由標籤、元素和屬性組成:1.標籤定義內容類型,用尖括號包圍,如。 2.元素由開始標籤、內容和結束標籤組成,如內容。 3.屬性在開始標籤中定義鍵值對,增強功能,如。這些是構建網頁結構的基本單位。

了解H5代碼:HTML5的基本原理了解H5代碼:HTML5的基本原理Apr 17, 2025 am 12:08 AM

HTML5是構建現代網頁的關鍵技術,提供了許多新元素和功能。 1.HTML5引入了語義化元素如、、等,增強了網頁結構和SEO。 2.支持多媒體元素和,無需插件即可嵌入媒體。 3.表單增強了新輸入類型和驗證屬性,簡化了驗證過程。 4.提供了離線和本地存儲功能,提升了網頁性能和用戶體驗。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境