In recent years, because mobile devices have good support for HTML5, there are often some activities that use the rewards. Recently, I am also reading H5 content and I have achieved one by myself, we will share this with you. 1. Effect 2. The principle is very simple. It is to add two canvases to the scratch area. The first canvas is used to display the content after the scratch. It can be an image or a string, the second canvas is used to display the coating. It can be filled with an image or solid color. The second canvas overwrites the first canvas. When you click or smear on the second canvas (Click and drag the mouse), the click area is transparent, so that you can see the content on the first canvas, that is, the effect of the prize is achieved. 3. Implementation (1) defines the Lottery class function Lottery (id, cover, coverType, width, height, drawPercentCallback) {this. conId = id; this. conNode = document. getElementById (this. conId); this. cover = cover | '# CCC'; this. coverType = coverType | 'color'; this. background = null; this. backCtx = null; this. mask = null; this. maskCtx = null; this. lottery = null; this. lotteryType = 'image'; this. width = width | 300; this. hei Ght = height | 100; this. clientRect = null; this. drawPercentCallback = drawPercentCallback;} to explain the parameters: id: The idcover of the scratch container: coating content, which can be an image address or color value. It can be blank. The default value is # ccccoverType: coating type, the value is image or color. It can be empty. The default value is colorwidth: the width of the scratch area. The default value is 300px. The value can be empty. height: the height of the scratch area. The default value is 100px. drawPercentCallback is empty: specifies the percentage callback of the area to be scaled out. If this parameter is left blank, the following variables are defined: background: The 2d context mask of the first canvas Element backCtx: background: the second canvas Element maskCtx: 2d context (context) of the mask element lottery: scratch The displayed content can be the image address or string lotteryType: the type of the content displayed after the scratch. The value is image or text. It must match the clientRect with lottery: getBoundingClientRect () value used to record the mask element (2) Add two canvas to the scratch container and obtain the 2d context this. background = this. background | this. createElement ('canvas ', {style: 'position: absolute; left: 0; top: 0;'}); this. mask = this. mask | this. createElement ('canvas ', {style: 'position: absolute; left: 0; top: 0;'}); if (! This. conNode. innerHTML. replace (/[\ w \ W] |/g, '') {this. conNode. appendChild (this. background); this. conNode. appendChild (this. mask); this. clientRect = this. conNode? This. conNode. getBoundingClientRect (): null; this. bindEvent ();} this. backCtx = this. backCtx | this. background. getContext ('2d '); this. maskCtx = this. maskCtx | this. mask. getContext ('2d '); The createElement tool method is used here, and events are bound, which will be described later. (3) draw the first canvas. The first canvas is divided into two types: image and string. If it is an image, use drawImage of canvas. If it is a string, fill it with white, then draw a string in the upper left and lower right places. The Code is as follows: if (this. lotteryType = 'image') {var image = new image (), _ this = this; Image. onload = function () {_ this. width = this. width; _ this. height = this. height; _ this. resizeCanvas (_ this. background, this. width, this. height); _ this. backCtx. drawImage (this, 0, 0);} image. src = this. lottery ;} Else if (this. lotteryType = 'text') {this. width = this. width; this. height = this. height; this. resizeCanvas (this. background, this. width, this. height); this. backCtx. save (); this. backCtx. fillStyle = '# fff'; this. backCtx. fillRect (0, 0, this. width, this. height); this. backCtx. restore (); this. backCtx. save (); var fontSize = 30; this. backCtx. font = 'bold '+ fontSize + 'px arial'; this. backCtx. textAlign = 'Center'; this. backCtx. fillStyle = '# f60'; this. backCtx. fillText (this. lottery, this. width/2, this. height/2 + fontSize/2); this. backCtx. restore ();} (4) Draw the second canvas. The second canvas is also divided into image or color filling. The difficulty here is how to make the mouse-clicked area transparent? The answer is: https://developer.mozilla.org/en/docs/Web/Guide/HTML/Canvas_tutorial/Compositing That is to say, we need to set globalCompositeOperation of maskCtx to destination-out. For detailed usage, refer to the above link. Therefore, the code for drawing the second canvas is as follows: this. resizeCanvas (this. mask, this. width, this. height); if (this. coverType = 'color') {this. maskCtx. fillStyle = this. cover; this. maskCtx. fillRect (0, 0, this. width, this. height); this. maskCtx. globalCompositeOperation = 'destination-out';} else if (this. coverType = 'image') {var image = new image (), _ this = this; Image. onload = function () {_ this. maskCtx. drawImage (this, 0, 0 ); _ This. maskCtx. globalCompositeOperation = 'destination-out';} image. src = this. cover;} resizeCanvas is a tool to change the canvas size. (5) After the binding event is drawn, bind the event to the second canvas. There is a distinction between mobile devices and PC-WEB. The mobile device is the touchstart and touchmove events, the corresponding PC-WEB is the keydown and mousemove events, in addition to the PC-WEB mode, to bind a mouseup event to the document, to determine whether the mouse is pressed. The Code is as follows: bindEvent: function () {var _ this = this; var device = (/android | webos | iphone | ipad | ipod | blackberry | iemobile | opera mini/I. test (navigator. userAgent. toLowerCase (); var clickEvtName = device? 'Touchstart': 'mousedown'; var moveEvtName = device? 'Touchmove ': 'mousemove'; if (! Device) {var isMouseDown = false; document. addEventListener ('mouseup', function (e) {isMouseDown = false ;}, false);} this. mask. addEventListener (clickEvtName, function (e) {isMouseDown = true; var docEle = document.doc umentElement; if (! _ This. clientRect) {_ this. clientRect = {left: 0, top: 0 };} var x = (device? E. touches [0]. clientX: e. clientX)-_ this. clientRect. left + docEle. scrollLeft-docEle. clientLeft; var y = (device? E. touches [0]. clientY: e. clientY)-_ this. clientRect. top + docEle. scrollTop-docEle. clientTop; _ this. drawPoint (x, y) ;}, false); this. mask. addEventListener (moveEvtName, function (e) {if (! Device &&! IsMouseDown) {return false;} var docEle = document.doc umentElement; if (! _ This. clientRect) {_ this. clientRect = {left: 0, top: 0 };} var x = (device? E. touches [0]. clientX: e. clientX)-_ this. clientRect. left + docEle. scrollLeft-docEle. clientLeft; var y = (device? E. touches [0]. clientY: e. clientY)-_ this. clientRect. top + docEle. scrollTop-docEle. clientTop; _ this. drawPoint (x, y) ;}, false) ;}here the mouse coordinates are taken out of the event and drawPoint is called for plotting. (6) Draw click and smear area the canvas radial gradient is used here, draw a circle from the place of the mouse, the Code is as follows: drawPoint: function (x, y) {this. maskCtx. beginPath (); var radgrad = this. maskCtx. createRadialGradient (x, y, 0, x, y, 30); radgrad. addColorStop (0, 'rgba (0.6, 0,) '); radgrad. addColorStop (1, 'rgba (255,255,255, 0) '); this. maskCtx. fillStyle = radgrad; this. maskCtx. arc (x, y, 30, 0, Math. PI * 2, true); this. maskCtx. fill (); if (this. drawPercentCallback) {This. drawPercentCallback. call (null, this. getTransparentPercent (this. maskCtx, this. width, this. height);} (7) percent of the smear area. In many cases, we also need to know the number of user smear and then perform the next interaction. For example, when the user smear 80%, to allow the next display. How can we calculate this percentage? In fact, it is very simple. We can use the getImageData method to specify the pixel data of the rectangle on the canvas. Because each pixel is represented by rgba, the area that has been smeared is transparent, therefore, we only need to determine whether the alpha channel value is transparent. The Code is as follows: getTransparentPercent: function (ctx, width, height) {var imgData = ctx. getImageData (0, 0, width, height), pixles = imgData. data, transPixs = []; for (var I = 0, j = pixles. length; I <j; I + = 4) {var a = pixles [I + 3]; if (a <128) {transPixs. push (I) ;}} return (transPixs. length/(pixles. length/4) * 100 ). toFixed (2);} (8) Call the entry init and finally provide an entry for drawing and resetting. The Code is as follows: init: function (lottery, lotteryTy Pe) {this. lottery = lottery; this. lotteryType = lotteryType | 'image'; this. drawLottery () ;}so far, all the key code has been explained.