Heim > Web-Frontend > H5-Tutorial > Tutorial zur Verwendung von HTML5 zum Erlernen des Radiergummi-Verschmiereffekts_html5-Tutorial-Fähigkeiten

Tutorial zur Verwendung von HTML5 zum Erlernen des Radiergummi-Verschmiereffekts_html5-Tutorial-Fähigkeiten

WBOY
Freigeben: 2016-05-16 15:46:37
Original
2220 Leute haben es durchsucht

Dieser Effekt wurde zufällig in einem aktuellen Projekt verwendet, das ein bisschen wie eine Rubbelkarte ist. Auf einem mobilen Gerät wird ein Bild freigerubbelt, um ein anderes Bild anzuzeigen. Die Darstellung ist wie folgt:
2015511163305472.png (974×840)

DEMO bitte rechts klicken: DEMO
Das kommt im Internet recht häufig vor. Ich wollte ursprünglich nur eine Demo online finden und seine Methode anwenden in Android Aufgrund der Kundenanforderungen ist es nicht erforderlich, dass es unter Android besonders flüssig läuft, zumindest muss es spielbar sein, aber die Demo, die ich online gefunden habe, ist zu verzögert und kann überhaupt nicht gespielt werden. Deshalb wollte ich einfach selbst einen schreiben, und dieser Artikel dient nur dazu, den Forschungsprozess aufzuzeichnen.

Das erste, was mir für diesen Scraping-Effekt einfällt, ist die Verwendung der HTML5-Leinwand. In der Canvas-API ist die ClearRect-Methode, die Pixel löschen kann, aber die ClearRect-Methode löscht schließlich das Flächenrechteck. Die meisten Menschen sind daran gewöhnt. Radiergummis sind rundum, daher wird die leistungsstarke Funktion des Beschneidungsbereichs eingeführt, nämlich die Clip-Methode. Die Verwendung ist ganz einfach:

XML/HTML-CodeInhalt in die Zwischenablage kopieren
  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();
  7. Der obige Code realisiert das Löschen eines kreisförmigen Bereichs, dh implementiert zunächst einen kreisförmigen Pfad, verwendet diesen Pfad dann als Beschneidungsbereich und löscht dann die Pixel. Beachten Sie, dass Sie zunächst die Zeichenumgebung speichern und nach dem Löschen der Pixel zurücksetzen müssen. Wenn Sie dies nicht tun, sind zukünftige Zeichnungen auf diesen Beschneidungsbereich beschränkt.

    Da der Löscheffekt nun vorhanden ist, ist es an der Zeit, den Löscheffekt der Mausbewegung zu beschreiben. Ich werde ihn unten mit der Maus beschreiben, da die mobile Version ähnlich ist, d. h. Mousedown durch Touchstart und Mousemove ersetzen mit touchmove und Mouseup mit touchend , und die Koordinatenpunkterfassung wird von e.clientX in e.targetTouches[0].pageX geändert.

    Um das Löschen von Mausbewegungen zu implementieren, dachte ich zuerst daran, den kreisförmigen Bereich zu löschen, in dem sich die Maus im Mousemove-Ereignis befindet, das ausgelöst wird, wenn sich die Maus bewegt Der Bereich ist nicht mehr kohärent und der folgende Effekt wird angezeigt. Dies ist offensichtlich nicht der Radiergummi-Effekt, den wir wollen.
    2015511163949198.jpg (1103×693)

    Da alle Punkte inkohärent sind, müssen Sie diese Punkte als Nächstes verbinden. Wenn Sie die Zeichenfunktion implementieren, können Sie die beiden Punkte direkt über lineTo verbinden und dann zeichnen, aber der Löscheffekt ist Der Beschneidungsbereich erfordert einen geschlossenen Pfad. Wenn Sie einfach zwei Punkte verbinden, kann der Beschneidungsbereich nicht gebildet werden. Dann dachte ich darüber nach, Berechnungsmethoden zu verwenden, um die vier Endpunktkoordinaten der Rechtecke in den beiden Löschbereichen zu berechnen, bei denen es sich um das rote Rechteck im Bild unten handelt:
    2015511164105508.png (343×129)

    Die Berechnungsmethode ist ebenfalls sehr einfach, da wir die Koordinaten der beiden Endpunkte der Linie kennen können, die die beiden Beschneidungsbereiche verbindet, und auch wissen können, wie breit die gewünschte Linie, die Koordinaten der vier Endpunkte des Rechtecks, werden leicht zu finden, daher gibt es unten den Code:
    XML/HTML-CodeInhalt in die Zwischenablage kopieren

    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;
    4. var y3 = y1-acos;
    5. var x4 = x1-asin;
    6. var y4 = y1 acos;
    7. var
    8. x5 = x2 asin;
    9. var
    10. y5 = y2-acos;
    11. var
    12. x6 = x2-asin;
    13. var
    14. y6 = y2 acos;

       x1, y1 und x2, y2 sind die beiden Endpunkte, daher werden die Koordinaten der vier Endpunkte erhalten. Auf diese Weise ist der Beschneidungsbereich ein Kreis plus ein Rechteck, und der Code ist wie folgt organisiert:
      XML/HTML-CodeKopieren Sie den Inhalt in die Zwischenablage

      1. var hastouch = "ontouchstart" in window?true:false,//bestimmen, ob Für mobile Geräte
      2.  tapstart = hastouch?"touchstart":"mousedown", 
      3.  tapmove = hastouch?"touchmove":"mousemove", 
      4. tapend = hastouch?"touchend":"mouseup"
      5. canvas.addEventListener(tapstart , function(e){
      6. e.preventDefault();
      7.  
      8.  x1 = hastouch?e.targetTouches[0].pageX:e.clientX-canvas.offsetLeft ;
      9.  y1 = hastouch?e.targetTouches[0].pageY:e.clientY-canvas.offsetTop ;
      10.  
      11. // Beim ersten Mausklick einen kreisförmigen Bereich löschen und gleichzeitig den ersten Koordinatenpunkt aufzeichnen
      12. ctx.save()
      13. ctx.beginPath()
      14. ctx.arc(x1,y1,a,0,2*Math.PI);
      15. ctx.clip()
      16. ctx.clearRect(0,0,canvas.width,canvas.height);
      17. ctx.restore();
      18.  
      19. canvas.addEventListener(tapmove, tapmoveHandler);
      20. canvas.addEventListener(tapend, function(){
      21. canvas.removeEventListener(tapmove, tapmoveHandler);
      22. });
      23. //Dieses Ereignis wird ausgelöst, wenn sich die Maus bewegt
      24. Funktion tapmoveHandler(e){
      25. e.preventDefault()
      26.  x2 = hastouch?e.targetTouches[0].pageX:e.clientX-canvas.offsetLeft ;
      27.  y2 = hastouch?e.targetTouches[0].pageY:e.clientY-canvas.offsetTop ;
      28.  
      29. //Die vier Endpunkte des Beschneidungsbereichs zwischen zwei Punkten abrufen
      30. var aasin = a*Math.sin(Math.atan((y2-y1)/(x2-x1)) );
      31. var aacos = a*Math.cos(Math.atan((y2-y1)/(x2-x1)) )
      32. var x3 = x1 asin;
      33. var y3 = y1-acos;
      34. var
      35. x4 = x1-asin;
      36. var
      37. y4 = y1 acos;
      38. var
      39. x5 = x2 asin;
      40. var
      41. y5 = y2-acos; var
      42. x6
      43. = x2-asin; var
      44. y6
      45. = y2 acos;  
      46. // Achten Sie auf die Kontinuität der Linien, zeichnen Sie also einen Kreis an einem Ende des Rechtecks ​​
      47. ctx.save()
      48. ctx.beginPath()
      49. ctx.arc(x2,y2,a,0,2*Math.PI);
      50. ctx.clip()
      51. ctx.clearRect(0,0,canvas.width,canvas.height);
      52. ctx.restore();
      53.  
      54. // Löschen Sie die Pixel im rechteckigen Beschneidungsbereich
      55. ctx.save()
      56. ctx.beginPath()
      57. ctx.moveTo(x3,y3);
      58. ctx.lineTo(x5,y5);
      59. ctx.lineTo(x6,y6);
      60. ctx.lineTo(x4,y4);
      61. ctx.closePath();
      62. ctx.clip()
      63. ctx.clearRect(0,0,canvas.width,canvas.height);
      64. ctx.restore();
      65.  
      66. //Letzte Koordinaten aufzeichnen
      67. x1 = x2;
      68. y1
      69. = y2; }
      70. })
      71. Auf diese Weise wird der Mauslöscheffekt erreicht, es muss jedoch noch ein weiterer Punkt erreicht werden, nämlich der Effekt, dass beim Löschen einer bestimmten Anzahl von Pixeln der gesamte Bildinhalt automatisch angezeigt wird Um diesen Effekt zu erzielen, verwende ich imgData. Der Code lautet wie folgt: Code kopieren
      XML/HTML-Code


      Inhalt in die Zwischenablage kopieren

      var
      imgData
      1. = ctx.getImageData(0,0,canvas.width,canvas. Höhe); var dd
      2. =
      3. 0; for(var x=
      4. 0
      5. ;x<imgData.width;x =1){ for(var y=
      6. 0
      7. ;y<imgData.height;y =1){ var i = (y*imgData.width x)*4;
      8. if(imgData.data[i 3]
      9. > 0){
      10. dd dd
      11.                                                               }
      12. }
      13. if(dd/(imgData.width*imgData.height)
      14. <
      15. 0.4
      16. ){
      17. canvas.className = "noOp";
      18. }
      19. Erhalten Sie imgData, durchlaufen Sie die Pixel in imgData und analysieren Sie dann das Alpha in RGBA im Datenarray von imgData, dh analysieren Sie die Transparenz. Wenn das Pixel gelöscht wird, ist die Transparenz 0, d. h. Es ist so Vergleichen Sie die Anzahl der Pixel mit einer Transparenz ungleich Null auf der aktuellen Leinwand mit der Gesamtzahl der Pixel auf der Leinwand. Wenn der Anteil der Pixel mit einer Transparenz ungleich Null weniger als 40 % beträgt, bedeutet dies, dass es mehr als 60 % gibt. des Bereichs auf der aktuellen Leinwand. Nach dem Löschen kann das Bild automatisch gerendert werden.

        Beachten Sie hier, dass ich den Code zum Überprüfen von Pixeln in das Mouseup-Ereignis eingefügt habe, da der Rechenaufwand relativ groß ist. Wenn der Benutzer wild mit der Maus klickt, wird das Mouseup-Ereignis wild ausgelöst, was bedeutet, dass er verrückt wird. Beim Auslösen dieser Schleife zur Pixelberechnung ist der Berechnungsaufwand so groß, dass er den Prozess blockiert und dazu führt, dass die Schnittstelle hängen bleibt. Die Lösung lautet wie folgt: Fügen Sie ein Timeout hinzu, um die Ausführung der Pixelberechnung zu verzögern, und löschen Sie das Timeout jedes Mal Wenn der Benutzer klickt, wird diese Berechnung nicht mehr ausgelöst. Eine andere Möglichkeit zur Verbesserung besteht darin, Pixel für Pixel zu überprüfen Wenn die Anzahl der Pixel zu groß ist, bleibt sie definitiv hängen. Sie können also eine Stichprobenprüfung durchführen, z. B. alle 30 Pixel überprüfen. Der geänderte Code lautet wie folgt:
        Code kopieren

        XML/HTML-CodeInhalt in die Zwischenablage kopieren
        1. timeout = setTimeout(function(){
        2. var imgData = ctx.getImageData(0,0,canvas.width,canvas.height);
        3. var dd = 0;
        4. for(var
        5. x=0;x<imgData.width;x =30){
        6. for(var
        7. y=0;y<imgData.height;y =30){
        8. var
        9. i = (y*imgData.width x)*4; if(imgData.data[i 3]
        10. >
        11. 0){ dd dd
        12.                                                               
        13.                                                              
        14. }
        15. if(dd/(imgData.width*imgData.height/900)
        16. <
        17. 0.4
        18. ){
        19. canvas.className =
        20. "noOp"
        21. ; } },100)
        22. Dadurch kann verhindert werden, dass Benutzer wild klicken. Wenn es andere bessere Überprüfungsmethoden gibt, geben Sie bitte Ihre Meinung ab. Vielen Dank.

          Zu diesem Zeitpunkt war alles geschrieben, und dann war es Zeit zum Testen. Es blieb immer noch auf Android hängen, also musste ich mir einen anderen Weg überlegen Der Standardwert dieser Eigenschaft ist „Source-Over“, das heißt, sie wird überlagert, wenn Sie auf vorhandenen Pixeln zeichnen. Es gibt jedoch auch eine Eigenschaft namens „Destination-Out“. Die offizielle Erklärung lautet: Zeigen Sie das Zielbild außerhalb an Quellbild. Nur der Teil des Zielbilds außerhalb des Quellbilds wird angezeigt und das Quellbild ist transparent. Es scheint schwer zu verstehen, aber wenn Sie es selbst testen, werden Sie feststellen, dass es sehr einfach ist. Das heißt, wenn Sie auf der Grundlage vorhandener Pixel zeichnen, werden die vorhandenen Pixel in dem von Ihnen gezeichneten Bereich transparent gemacht Sie können es direkt ändern, indem Sie sich das Bild ansehen. Leicht verständlich:
          2015511164219714.jpg (553×390)

          Veranschaulichung der Wirkung des globalCompositeOperation-Attributs.
          Mit diesem Attribut bedeutet dies, dass kein Clip verwendet werden muss und dass zur Berechnung des Clipping-Bereichs kein Sin- oder Cos-Wert verwendet werden muss. Verwenden Sie einfach eine dicke Linie, was die Kosten erheblich reduzieren kann Die Berechnung wird reduziert und die Aufrufe an die Zeichenumgebungs-API werden reduziert. Die Leistung wird verbessert und die Ausführung unter Android sollte viel reibungsloser sein. Der folgende Code ist geändert:


          XML/HTML-CodeInhalt in die Zwischenablage kopieren
          1. //Erzielen Sie einen Löscheffekt durch Ändern von globalCompositeOperation
          2. Funktion tapClip(){
          3. var hastouch = "ontouchstart" in window?true:false,
          4.  tapstart = hastouch?"touchstart":"mousedown", 
          5.  tapmove = hastouch?"touchmove":"mousemove", 
          6. tapend = hastouch?"touchend":"mouseup"
          7.  
          8. canvas.addEventListener(tapstart, function(e){
          9. clearTimeout(timeout)
          10. e.preventDefault();
          11.  
          12.  x1 = hastouch?e.targetTouches[0].pageX:e.clientX-canvas.offsetLeft ;
          13.  y1 = hastouch?e.targetTouches[0].pageY:e.clientY-canvas.offsetTop ;
          14.  
          15.  ctx.lineCap = "round"; //Setze beide Enden der Linie als Bögen
          16.  ctx.lineJoin = "round"; //Setzen Sie die Liniendrehung auf Bogen
          17. ctx.lineWidth = a*2;
          18. ctx.globalCompositeOperation = "destination-out";  
          19. ctx.save();
          20. ctx.beginPath()
          21. ctx.arc(x1,y1,1,0,2*Math.PI);
          22. ctx.fill();
          23. ctx.restore();
          24.  
          25. canvas.addEventListener(tapmove, tapmoveHandler);
          26. canvas.addEventListener(tapend, function(){
          27. canvas.removeEventListener(tapmove, tapmoveHandler);
          28.                                                       
          29.    
          30. timeout
          31. =
          32. setTimeout
          33. (function(){
          34.             var imgData = ctx.getImageData(0,0,canvas.width,canvas.height);   
          35.             var dd = 0;   
          36.             for(var x=0;x<imgData.width;x =30){   
          37.                 for(var y=0;y<imgData.height;y =30){   
          38.                       var i = (y*imgData.width   x)*4;   
          39.                     if(imgData.data[i 3] > 0){   
          40.                         dd   
          41.                     }   
          42.                 }   
          43.             }   
          44.             if(dd/(imgData.width*imgData.height/900)<0.4){   
          45.                 canvas.className = "noOp";   
          46.             }   
          47.        },100)   
          48.         });   
          49.         function tapmoveHandler(e){   
          50.             e.preventDefault()   
          51.             x2 = hastouch?e.targetTouches[0].pageX:e.clientX-canvas.offsetLeft ;   
          52.             y2 = hastouch?e.targetTouches[0].pageY:e.clientY-canvas.offsetTop ;   
          53.                
          54.             ctx.save();   
          55.             ctx.moveTo(x1,y1);   
          56.             ctx.lineTo(x2,y2);   
          57.             ctx.Stroke();   
          58.             ctx.restore()   
          59.                
          60.             x1 = x2;   
          61.             y1 = y2;   
          62.         }   
          63.     })   
          64. }   

            擦除那部分代码就这么一点,也就相当于画图功能,直接设置line属性后通过lineTo进行绘制线Sie haben die globaleCompositeOperation-Funktion „destination-out“ verwendet und können die Funktion „destination-out“ verwenden了擦除效果.鼠标滑动触发的事件里面代码也少了很多,绘图对象的调用次数减少了,计算也减少了,性能提升大大滴.

            改好代码后就立即用自己的android机子测试了一下, 果然如此,跟上一个相比,流畅了很多,至少达到了客户要求的能玩的地步了.

            源码地址:https://github.com/whxaxes/canvas-test/blob/gh-pages/src/Funny-demo/clip/clip.html

    Verwandte Etiketten:
    Quelle:php.cn
    Erklärung dieser Website
    Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage