Maison  >  Article  >  interface Web  >  Introduction à la gestion des événements dans HTML5 Canvas

Introduction à la gestion des événements dans HTML5 Canvas

不言
不言original
2018-06-05 10:45:101169parcourir

Cet article présente principalement le traitement des événements de HTML5 Canvas. Cet article explique les limites de Canvas, la liaison des événements aux éléments Canvas, la méthode isPointInPath, le redessinage des boucles et le bouillonnement d'événements, etc. Les amis dans le besoin peuvent s'y référer

DOM est une partie très importante du domaine du front-end Web. Il est utilisé non seulement lors du traitement des éléments HTML, mais également dans la programmation graphique. Par exemple, dans le dessin SVG, divers graphiques sont insérés dans la page sous forme de nœuds DOM, ce qui signifie que les graphiques peuvent être manipulés à l'aide des méthodes DOM. Par exemple, s'il existe un élément b0df1a4bdae36d21726841c97f474466, vous pouvez directement utiliser jquery pour ajouter un événement de clic $('#p1').click(function(){…})". Cependant, cette méthode de traitement DOM n'est pas adaptée au HTML5. Elle n'est plus applicable dans Canvas. Canvas utilise un autre ensemble de mécanismes. Quel que soit le nombre de graphiques dessinés sur Canvas, Canvas est un tout. Les graphiques eux-mêmes font en fait partie de Canvas et ne peuvent pas l'être. obtenu séparément, il ne peut donc pas être directement donné à quelqu'un. Les graphiques ajoutent des événements JavaScript

Limitations de Canvas

Dans Canvas, tous les graphiques sont dessinés sur le cadre, et la méthode de dessin ne traitera pas les éléments graphiques dessinés comme même si la valeur de retour est affichée, js ne peut pas obtenir les éléments graphiques dessinés. Par exemple :

Copier le code
<.>

Le code est le suivant :

cvs = document.getElementById(&#39;mycanvas&#39;);
ctx = canvas.getContext(&#39;2d&#39;);
theRect = ctx.rect(10, 10, 100, 100);
ctx.stroke();
console.log(theRect);     //undefined
Ce code dessine un rectangle dans la balise canvas Tout d'abord, vous pouvez voir que la méthode rect pour dessiner des graphiques n'a pas de valeur de retour If. vous ouvrez les outils de développement du navigateur, vous pouvez également voir qu'aucun contenu n'est ajouté à l'intérieur de la balise canvas et le contexte actuel obtenu dans js n'ont aucun contenu indiquant les nouveaux graphiques

Par conséquent. , les méthodes dom couramment utilisées dans le front-end ne sont pas applicables dans Canvas. Par exemple, cliquez sur le rectangle Canvas ci-dessus, le clic réel est l'intégralité de l'élément Canvas

Lier les événements au Canvas. element

Étant donné que l'événement ne peut atteindre que le niveau de l'élément Canvas, si vous souhaitez aller plus loin, pour identifier sur quel graphique à l'intérieur du Canvas le clic a eu lieu, vous devez ajouter du code pour le traitement. L'idée est la suivante : lier un événement à l'élément Canvas, lorsque l'événement se produit, vérifier la position de l'objet événement, puis vérifier quels graphiques sont couverts. Par exemple, dans l'exemple ci-dessus, un rectangle est dessiné, qui couvre la plage de. 10-110 sur l'axe des x et 10-110 sur l'axe des y. Tant que la souris est cliquée dans cette plage, cela peut être considéré comme un clic sur le rectangle. Vous pouvez déclencher manuellement l'événement de clic qui doit être. traité par le rectangle. L'idée est en fait relativement simple, mais la mise en œuvre est encore un peu compliquée. Non seulement il faut considérer l'efficacité de ce processus de jugement, mais aussi le type d'événement doit être réévalué à certains endroits, et un la capture à l'intérieur du Canvas doit être redéfinie et le mécanisme de bouillonnement

La première chose à faire est de lier un événement à l'élément Canvas. Par exemple, si vous souhaitez lier un événement de clic à un graphique à l'intérieur du Canvas. , vous devez proxy l'événement via l'élément Canvas :

Copier le code

Le code est le suivant :

cvs = document.getElementById(&#39;mycanvas&#39;);
cvs.addEventListener(&#39;click&#39;, function(e){
  //...
}, false);
Ensuite, vous devez déterminer l'emplacement où l'objet événement se produit, les layerX et layerY de l'objet événement e Les propriétés représentent les coordonnées dans le système de coordonnées interne du Canvas. Cependant, Opera ne prend pas en charge cet attribut et Safari prévoit de le supprimer. Nous devons donc créer des méthodes d'écriture compatibles :

Copier le code

Le code est le suivant :

function getEventPosition(ev){
  var x, y;
  if (ev.layerX || ev.layerX == 0) {
    x = ev.layerX;
    y = ev.layerY;
  } else if (ev.offsetX || ev.offsetX == 0) { // Opera
    x = ev.offsetX;
    y = ev.offsetY;
  }
  return {x: x, y: y};
}
//Remarque : Pour utiliser la fonction ci-dessus, vous devez définir la position de l'élément Canvas sur absolue.


Maintenant que nous avons la position des coordonnées de l'objet événement, nous devons déterminer quels graphiques dans le canevas couvrent cette coordonnée.

Méthode isPointInPath

La méthode isPointInPath de Canvas peut déterminer si le graphique de contexte actuel couvre une certaine coordonnée, telle que :

Copiez le code

Le code est le suivant :

cvs = document.getElementById(&#39;mycanvas&#39;);
ctx = canvas.getContext(&#39;2d&#39;);
ctx.rect(10, 10, 100, 100);
ctx.stroke();
ctx.isPointInPath(50, 50);     //true
ctx.isPointInPath(5, 5);     //false
Ensuite, ajoutez un jugement d'événement pour déterminer si un événement de clic se produit sur le rectangle :

Copiez le code

Le code est le suivant :

cvs.addEventListener(&#39;click&#39;, function(e){
 p = getEventPosition(e);
 if(ctx.isPointInPath(p.x, p.y)){
   //点击了矩形
 }
}, false);
Ce qui précède est la méthode de base de manipulation de Canvas événements, mais le code ci-dessus a encore des limites, puisque la méthode isPointInPath ne détermine le chemin que dans le contexte actuel, donc lorsque plusieurs graphiques ont été dessinés dans le canevas, l'événement ne peut être déterminé qu'en fonction du contexte du dernier graphique, tel que comme :

Copiez le code

Le code est le suivant :

cvs = document.getElementById(&#39;mycanvas&#39;);
ctx = canvas.getContext(&#39;2d&#39;);
ctx.beginPath();
ctx.rect(10, 10, 100, 100);
ctx.stroke();
ctx.isPointInPath(20, 20);     //true
ctx.beginPath();
ctx.rect(110, 110, 100, 100);
ctx.stroke();
ctx.isPointInPath(150, 150);     //true
ctx.isPointInPath(20, 20);     //false
Comme vous pouvez le voir sur le ci-dessus, la méthode isPointInPath ne peut identifier le chemin graphique que dans le contexte actuel. Le chemin précédemment tracé ne peut pas être jugé rétrospectivement. La solution à ce problème est la suivante : lorsqu'un événement de clic se produit, redessinez tous les graphiques et utilisez la méthode isPointInPath pour chacun dessiné afin de déterminer si les coordonnées de l'événement se trouvent dans la couverture des graphiques.

Redessin de boucle et bouillonnement d'événements

Afin de mettre en œuvre le redessin de boucle, les paramètres de base du graphique doivent être enregistrés au préalable :


复制代码

代码如下:

arr = [
 {x:10, y:10, width:100, height:100},
 {x:110, y:110, width:100, height:100}
];

cvs = document.getElementById(&#39;mycanvas&#39;);
ctx = canvas.getContext(&#39;2d&#39;);

draw();

function draw(){
 ctx.clearRech(0, 0, cvs.width, cvs.height);
 arr.forEach(function(v){
   ctx.beginPath();
   ctx.rect(v.x, v.y, v.width, v.height);
   ctx.stroke();
 });
}

上面的代码事先将两个矩形的基本参数保存下来,每次调用draw方法,就会循环调用这些基本参数,用于绘制两个矩形。这里还使用了clearRect方法,用于在重绘时清空画布。接下来要做的是增加事件代理,以及在重绘时对每一个上下文环境使用isPointInPath方法:

复制代码

代码如下:

cvs.addEventListener(&#39;click&#39;, function(e){
 p = getEventPosition(e);
 draw(p);
}, false);

事件发生时,将事件对象的坐标传给draw方法处理。这里还需要对draw方法做一些小改动:

复制代码

代码如下:

function draw(p){
 var who = [];
 ctx.clearRech(0, 0, cvs.width, cvs.height);
 arr.forEach(function(v, i){
   ctx.beginPath();
   ctx.rect(v.x, v.y, v.width, v.height);
   ctx.stroke();
   if(p && ctx.isPointInPath(p.x, p.y)){
     //如果传入了事件坐标,就用isPointInPath判断一下
     //如果当前环境覆盖了该坐标,就将当前环境的index值放到数组里
     who.push(i);
   }
 });
 //根据数组中的index值,可以到arr数组中找到相应的元素。
 return who;
}

在上面代码中,点击事件发生时draw方法会执行一次重绘,并在重绘过程中检查每一个图形是否覆盖了事件坐标,如果判断为真,则视为点击了该图形,并将该图形的index值放入数组,最后将数组作为draw方法的返回值。在这种处理机制下,如果Canvas里有N个图形,它们有一部分是重叠的,而点击事件恰巧发生在这个重叠区域上,那么draw方法的返回数组里会有N个成员。这时就有点类似事件冒泡的情况,数组的最后一个成员处于Canvas最上层,而第一个成员则在最下层,我们可以视为最上层的成员是e.target,而其他成员则是冒泡过程中传递到的节点。当然这只是最简单的一种处理方法,如果真要模拟DOM处理,还要给图形设置父子级关系。

以上就是Canvas事件处理的基本方法。在实际运用时,如何缓存图形参数,如何进行循环重绘,以及如何处理事件冒泡,都还需要根据实际情况花一些心思去处理。另外,click是一个比较好处理的事件,相对麻烦的是mouseover、mouseout和mousemove这些事件,由于鼠标一旦进入Canvas元素,始终发生的都是mousemove事件,所以如果要给某个图形单独设置mouseover或mouseout,还需要记录鼠标移动的路线,给图形设置进出状态。由于处理的步骤变得复杂起来,必须对性能问题提高关注。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
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