Maison > interface Web > Tutoriel H5 > le corps du texte

Tutoriel sur l'utilisation de HTML5 pour obtenir les compétences du didacticiel effect_html5 sur l'effet de maculage de la gomme

WBOY
Libérer: 2016-05-16 15:46:37
original
2193 Les gens l'ont consulté

Cet effet vient d'être utilisé dans un projet récent, qui s'apparente un peu à une carte à gratter Sur un appareil mobile, une image est grattée pour en afficher une autre. Le rendu est le suivant :
2015511163305472.png (974×840)

DEMO veuillez cliquer à droite : DEMO
C'est assez courant sur Internet. Au départ, je voulais simplement trouver une démo en ligne et appliquer sa méthode. Après l'avoir appliquée, j'ai découvert cela. sous Android En raison des exigences des clients, il n'est pas nécessaire qu'il soit particulièrement fluide sur Android, au moins il doit être jouable, mais la démo que j'ai trouvée en ligne est trop lente et ne peut pas être lue du tout. Je voulais juste en écrire un moi-même, et cet article sert uniquement à enregistrer le processus de recherche.

La première chose qui vient à l'esprit pour cet effet de scraping est d'utiliser le canevas HTML5. Dans l'API canvas, la méthode clearRect qui peut effacer les pixels est la méthode clearRect, mais la méthode clearRect efface le rectangle de la zone. la plupart des gens y sont habitués. Les gommes sont polyvalentes, c'est pourquoi la fonction puissante de la zone de découpage est introduite, qui est la méthode de découpage. L'utilisation est très simple :

Code XML/HTMLCopier le contenu dans le presse-papiers
  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();

Le code ci-dessus réalise l'effacement d'une zone circulaire, c'est-à-dire qu'il implémente d'abord un chemin circulaire, puis utilise ce chemin comme zone de découpage, puis efface les pixels. Une chose à noter est que vous devez d'abord enregistrer l'environnement de dessin et réinitialiser l'environnement de dessin après avoir effacé les pixels. Si vous ne réinitialisez pas, les futurs dessins seront limités à cette zone de découpage.

Maintenant que l'effet d'effacement est là, il est maintenant temps d'écrire l'effet d'effacement du mouvement de la souris. Je vais utiliser la souris pour le décrire ci-dessous, car la version mobile est similaire, c'est-à-dire remplacer mousedown par touchstart, mousemove. avec touchmove et mouseup avec touchend , et l'acquisition du point de coordonnées passe de e.clientX à e.targetTouches[0].pageX.

Pour implémenter l'effacement des mouvements de la souris, j'ai d'abord pensé à effacer la zone circulaire où se trouve la souris dans l'événement mousemove déclenché lorsque la souris bouge. Après l'avoir écrit, j'ai constaté que lorsque la souris se déplace très rapidement, l'effacement est effacé. La zone n'est plus cohérente, et l'effet suivant apparaîtra. Ce n'est évidemment pas l'effet de gomme souhaité.
2015511163949198.jpg (1103×693)

Comme tous les points sont incohérents, la prochaine chose à faire est de connecter ces points. Si vous implémentez la fonction de dessin, vous pouvez directement connecter les deux points via lineTo puis dessiner, mais l'effet d'effacement est la zone de découpage. nécessite un chemin fermé. Si vous connectez simplement deux points, la zone de découpage ne peut pas être formée. Ensuite, j'ai pensé à utiliser des méthodes de calcul pour calculer les quatre coordonnées finales des rectangles dans les deux zones d'effacement, qui est le rectangle rouge dans l'image ci-dessous :
2015511164105508.png (343×129)

La méthode de calcul est également très simple, car on peut connaître les coordonnées des deux extrémités de la ligne reliant les deux zones de détourage, et aussi savoir quelle largeur la ligne que l'on veut, les coordonnées des quatre extrémités du rectangle deviennent facile à trouver, il y a donc le code ci-dessous :
Code XML/HTMLCopier le contenu dans le presse-papiers

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

     x1, y1 et x2, y2 sont les deux points finaux, ainsi les coordonnées des quatre points finaux sont obtenues. De cette façon, la zone de découpage est un cercle plus un rectangle, et le code est organisé comme suit :
    Code XML/HTMLCopier le contenu dans le presse-papier

    1. var hastouch = "ontouchstart" dans window?true:false,//déterminer si Pour les appareils mobiles
    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.  
    9. x1 = hastouch?e.targetTouches[0].pageX:e.clientX-canvas.offsetLeft ;
    10.  
    11. y1 = hastouch?e.targetTouches[0].pageY:e.clientY-canvas.offsetTop ;
    12.  
    13. // Efface une zone circulaire lors du premier clic avec la souris, et enregistre le premier point de coordonnées en même temps
    14. ctx.save()
    15. ctx.beginPath()
    16. ctx.arc(x1,y1,a,0,2*Math.PI);
    17. ctx.clip()
    18. ctx.clearRect(0,0,canvas.width,canvas.height);
    19. ctx.restore();
    20.  
    21. canvas.addEventListener(tapmove, tapmoveHandler);
    22. canvas.addEventListener(tapend, function(){
    23. canvas.removeEventListener(tapmove, tapmoveHandler);
    24. });
    25. //Cet événement est déclenché lorsque la souris bouge
    26. fonction tapmoveHandler(e){
    27. e.preventDefault()
    28.  x2 = hastouch?e.targetTouches[0].pageX:e.clientX-canvas.offsetLeft ;
    29.  y2 = hastouch?e.targetTouches[0].pageY:e.clientY-canvas.offsetTop ;
    30.  
    31. //Obtenir les quatre extrémités de la zone de découpage entre deux points
    32. var aasin = a*Math.sin(Math.atan((y2-y1)/(x2-x1)) );
    33. var aacos = a*Math.cos(Math.atan((y2-y1)/(x2-x1)) )
    34. var x3 = x1 asin;
    35. var y3 = y1-acos;
    36. var
    37. x4 = x1-asin
    38. var
    39. y4 = y1 acos; var
    40. x5
    41. = x2 asin; var
    42. y5
    43. = y2-acos; var x6
    44. =
    45. x2-asin var y6
    46. =
    47. y2 acos;   // Assurer la continuité des lignes, tracez donc un cercle à une extrémité du rectangle
    48. ctx.save()
    49. ctx.beginPath()
    50. ctx.arc(x2,y2,a,0,2*Math.PI);
    51. ctx.clip()
    52. ctx.clearRect(0,0,canvas.width,canvas.height);
    53. ctx.restore();
    54.  
    55. // Efface les pixels dans la zone de découpage rectangulaire
    56. ctx.save()
    57. ctx.beginPath()
    58. ctx.moveTo(x3,y3);
    59. ctx.lineTo(x5,y5);
    60. ctx.lineTo(x6,y6);
    61. ctx.lineTo(x4,y4);
    62. ctx.closePath();
    63. ctx.clip()
    64. ctx.clearRect(0,0,canvas.width,canvas.height);
    65. ctx.restore();
    66.  
    67. //Enregistre les dernières coordonnées
    68. x1 = x2
    69. y1 = y2
    70. }
    71. })
    De cette façon, l'effet d'effacement de la souris est obtenu, mais il y a un autre point à atteindre, qui est l'effet de la plupart des effacements. Lorsque vous effacez un certain nombre de pixels, tout le contenu de l'image sera automatiquement affiché, ceci. effet, j'utilise imgData pour y parvenir. Le code est le suivant :
    Copier le code


    Code XML/HTML
    Copier le contenu dans le presse-papiers
    1. var imgData = ctx.getImageData(0,0,canvas.width,canvas. hauteur);
    2. var
    3. dd = 0 ;
    4. pour(var
    5. x=0;x<imgData.width;x =1){
    6. pour(var
    7. y=0;y<imgData.height;y =1){
    8. var
    9. i = (y*imgData.width x)*4
    10. if(imgData.data[i 3]
    11. > 0){
    12. jj jj
    13.                                                              
    14. }
    15. }
    16. if(dd/(imgData.width*imgData.height)
    17. <
    18. 0.4){
    19. canvas.className
    20. = "noOp" }
    21. Obtenez imgData, parcourez les pixels dans imgData, puis analysez l'alpha en rgba dans le tableau de données de imgData, c'est-à-dire analysez la transparence si le pixel est effacé, la transparence sera de 0, c'est-à-dire que c'est pour. comparez le nombre de pixels avec une transparence non nulle dans le canevas actuel au nombre total de pixels sur le canevas. Si la proportion de pixels avec une transparence non nulle est inférieure à 40 %, cela signifie qu'il y en aura plus de 60 %. de la zone sur la toile actuelle. Une fois effacée, l’image peut être automatiquement présentée.

      Notez ici que j'ai mis le code pour vérifier les pixels dans l'événement mouseup, car la quantité de calcul est relativement importante. Si l'utilisateur clique sauvagement sur la souris, l'événement mouseup sera déclenché de manière extravagante, ce qui signifie qu'il sera fou. En déclenchant cette boucle pour calculer les pixels, la quantité de calcul est si importante qu'elle bloque le processus et bloque l'interface. La solution est la suivante : ajoutez un délai d'attente pour retarder l'exécution du calcul des pixels et effacez le délai d'attente à chaque fois. fois que l'utilisateur clique, c'est-à-dire si l'utilisateur clique pendant une longue période. Rapidement, ce calcul ne sera plus déclenché. Une autre façon d'améliorer est de faire des inspections aléatoires. La façon dont je l'ai écrit ci-dessus est de vérifier pixel par pixel. le nombre de pixels est trop grand, il restera certainement bloqué, vous pouvez donc utiliser une inspection aléatoire, telle que Vérifier tous les 30 pixels. Le code modifié est le suivant :
      Copier le code

      .
      Code XML/HTMLCopier le contenu dans le presse-papiers
      1. timeout = setTimeout(function(){
      2. var imgData = ctx.getImageData(0,0,canvas.width,canvas.height);
      3. var dd = 0
      4. pour(var x=0;x<imgData.width;x =30){
      5. pour(var y=0;y<imgData.height;y =30){
      6. var i = (y*imgData.width x)*4
      7. if(imgData.data[i 3] >0){
      8. jj jj
      9.                                                                 
      10.                                                              
      11. }
      12. if(dd/(imgData.width*imgData.height/900)
      13. <
      14. 0.4){
      15. canvas.className
      16. = "noOp" }
      17. },100)
      18. Cela peut empêcher au maximum les utilisateurs de cliquer de manière extravagante. S'il existe d'autres méthodes de vérification plus efficaces, veuillez donner votre avis, merci.

        A cette étape, tout était écrit, puis il était temps de tester. Les résultats n'étaient toujours pas optimistes sur Android, j'ai donc dû penser à une autre façon. Finalement, j'ai découvert l'attribut globalCompositeOperation dans le fichier. environnement de dessin. La valeur par défaut de cette propriété est source-over, c'est-à-dire qu'elle sera superposée lorsque vous dessinez sur des pixels existants, mais il existe également une propriété appelée destination-out. L'explication officielle est : afficher l'image de destination en dehors de l'environnement de dessin. image source. Seule la partie de l'image cible en dehors de l'image source sera affichée et l'image source est transparente. Cela semble difficile à comprendre, mais en fait, si vous le testez vous-même, vous constaterez que c'est très simple, c'est-à-dire que lorsque vous dessinez sur la base de pixels existants, les pixels existants dans la zone que vous dessinez deviendront transparents. peut le changer directement en regardant la photo Facile à comprendre :
        2015511164219714.jpg (553×390)

        Illustration de l'effet de l'attribut globalCompositeOperation.
        Avec cet attribut, cela signifie qu'il n'est pas nécessaire d'utiliser le clip, et qu'il n'est pas nécessaire d'utiliser sin ou cos pour calculer la zone de découpage, utilisez simplement une ligne épaisse, ce qui peut réduire considérablement le coût. le calcul est réduit et les appels à l'API de l'environnement de dessin sont réduits. Les performances sont améliorées et l'exécution sur Android devrait être beaucoup plus fluide. Voici le code modifié :

        .


        Code XML/HTMLCopier le contenu dans le presse-papiers
        1. //Obtenir un effet d'effacement en modifiant globalCompositeOperation
        2. fonction tapClip(){
        3. var hastouch = "ontouchstart" dans 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(délai d'attente)
        10. e.preventDefault();
        11.  
        12.  
        13. x1 = hastouch?e.targetTouches[0].pageX:e.clientX-canvas.offsetLeft ;
        14.  
        15. y1 = hastouch?e.targetTouches[0].pageY:e.clientY-canvas.offsetTop ;
        16.  
        17.  
        18. ctx.lineCap = "round" //Définit les deux extrémités de la ligne sous forme d'arcs
        19.  
        20. ctx.lineJoin = "round" // Définit la ligne tournant en arc
        21. ctx.lineWidth = a*2;
        22. ctx.globalCompositeOperation
        23. = "destination-sortie"  
        24. ctx.save();
        25. ctx.beginPath()
        26. ctx.arc(x1,y1,1,0,2*Math.PI);
        27. ctx.fill();
        28. ctx.restore();
        29.  
        30. canvas.addEventListener(tapmove, tapmoveHandler);
        31. canvas.addEventListener(tapend, function(){
        32. canvas.removeEventListener(tapmove, tapmoveHandler);
        33.                                                        
        34.    
        35. timeout
        36. =
        37. setTimeout(function(){
        38.             var imgData = ctx.getImageData(0,0,canvas.width,canvas.height);   
        39.             var dd = 0;   
        40.             pour(var x=0;x<imgData.width;x =30){   
        41.                 pour(var y=0;y<imgData.height;y =30){   
        42.                       var i = (y*imgData.width   x)*4;   
        43.                     if(imgData.data[i 3] > 0){   
        44.                         dd   
        45.                     }   
        46.                 }   
        47.              }   
        48.             if(dd/(imgData.width*imgData.height/900)<0.4){   
        49.                 canvas.className = "noOp";   
        50.              }   
        51.        },100)   
        52.         });   
        53.         fonction tapmoveHandler(e){   
        54.             e.preventDefault()   
        55.             x2 = hastouch?e.targetTouches[0].pageX:e.clientX-canvas.offsetLeft ;   
        56.             y2 = hastouch?e.targetTouches[0].pageY:e.clientY-canvas.offsetTop ;   
        57.                
        58.             ctx.save();   
        59.             ctx.moveTo(x1,y1);   
        60.             ctx.lineTo(x2,y2);   
        61.             ctx.Stroke();   
        62.             ctx.restore()   
        63.                
        64.             x1 = x2;   
        65.             y1 = y2;   
        66.         }   
        67.     })   
        68. }   

          擦除那部分代码就这么一点,也就相当于画图功能,直接设置line属性后通过lineTo进行绘制线Il s'agit d'une opération globaleCompositeOperation avec destination-out, et d'un service globalCompositeOperation.了擦除效果。鼠标滑动触发的事件里面代码也少了很多,绘图对象的调用次数减少了,计算也减少了,性能提升大大滴。

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

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

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!