1. Code
  2. JavaScript

Manipulando el Canvas HMLT5 Usando Konva: Parte 5, Eventos

Si has estado siguiendo esta serie desde el principio, ahora deberías estar muy cómodo con formas, grupos, y capas. También deberías poder dibujar fácilmente algunas formas básicas y complejas sobre el lienzo usando Konva. Si planeas usar Konva para crear algunas aplicaciones interactivas o juegos, aprender como enlazar eventos a diferentes formas sobre el escenario es el siguiente paso lógico.
Scroll to top
8 min read
This post is part of a series called Manipulating HTML5 Canvas Using Konva.
Manipulating HTML5 Canvas Using Konva: Part 4, Styling

Spanish (Español) translation by Rafael Chavarría (you can also view the original English article)

Si has estado siguiendo esta serie desde el principio, ahora deberías estar muy cómodo con formas, grupos, y capas. También deberías poder dibujar fácilmente algunas formas básicas y complejas sobre el lienzo usando Konva. Si planeas usar Konva para crear algunas aplicaciones interactivas o juegos, aprender como enlazar eventos a diferentes formas sobre el escenario es el siguiente paso lógico.

En este tutorial, aprenderás cómo enlazar eventos a cualquier forma usando Konva. También aprenderás sobre delegación y propagación de eventos. Algunas veces, podrías necesitar el control de la región de toque de una forma así como disparar eventos mediante programación. Estaremos discutiendo estos dos temas también.

Enlazando Eventos a una Forma

Puedes enlazar diferentes eventos a cualquier forma usando Konva con la ayuda del método on(). Todo lo que tienes que hacer es pasar el nombre del evento como el primer parámetro de la función para ser ejecutado cuando el evento ocurra como el segundo parámetro. Puedes usar Konva para detectar  mouseup, mousedown, mouseenter, mouseleave, mouseover, mousemove, click, y dblclick. Adicionalmente, Konva te permite detectar eventos wheel, dragstart, dragmove, y dragend.

Aquí está un ejemplo que detecta eventos mousedown y mouseleave sobre un polígono regular (hexágono). De manera similar el círculo más pequeño está atado a los eventos mouseover y mouseup y el círculo más grande está atado a los eventos mouseenter, mouseleave, y mousemove.

1
var canvasWidth = 600;
2
var canvasHeight = 400;
3
4
var stage = new Konva.Stage({
5
  container: "example",
6
  width: canvasWidth,
7
  height: canvasHeight
8
});
9
10
var layerA = new Konva.Layer();
11
12
var polyA = new Konva.RegularPolygon({
13
  x: 125,
14
  y: 125,
15
  sides: 6,
16
  radius: 80,
17
  fill: "yellow",
18
  stroke: "black",
19
  strokeWidth: 5
20
});
21
22
var circA = new Konva.Circle({
23
  x: 275,
24
  y: 225,
25
  height: 100,
26
  fill: "orange",
27
  stroke: "black"
28
});
29
30
var circB = new Konva.Circle({
31
  x: 475,
32
  y: 275,
33
  radius: 100,
34
  fill: "red",
35
  stroke: "black"
36
});
37
38
layerA.add(polyA, circA, circB);
39
40
stage.add(layerA);
41
42
polyA.on("mousedown", function() {
43
  polyA.sides(polyA.sides() + 1);
44
  layerA.draw();
45
});
46
47
polyA.on("mouseleave", function() {
48
  var totalSides = polyA.sides();
49
  if(totalSides > 3) {
50
    polyA.sides(polyA.sides() - 1);
51
  }
52
  layerA.draw();
53
});
54
55
circA.on("mouseover", function() {
56
  circA.strokeWidth(10);
57
  layerA.draw();
58
});
59
60
circA.on("mouseup", function() {
61
  circA.strokeWidth(5);
62
  layerA.draw();
63
});
64
65
circB.on("mouseenter", function() {
66
  stage.container().style.cursor = "crosshair";
67
});
68
69
circB.on("mouseleave", function() {
70
  stage.container().style.cursor = "default";
71
});
72
73
circB.on("mousemove", function() {
74
  var pointerPos = stage.getPointerPosition();
75
  var r = pointerPos.x % 255;
76
  var g = pointerPos.y % 255;
77
  circB.fill("rgb(" + r + ", " + g + ", 100)");
78
  layerA.draw();
79
});

Si un usuario presiona cualquier botón del ratón mientras el cursor está dentro del polígono regular, incrementamos el número de lados del polígono en 1. El método sides() puede ser usado sin parámetro para obtener el número de lados para un polígono o usado con parámetro para establecer el número de lados de un polígono. También puedes obtener el número de lados usando getSides() y establecer el número de lados usando setSides(). Los lados del polígono son reducidos en uno cada vez que el cursor del ratón abandona el polígono.

Para el círculo más pequeño, el evento mouseover es usado para establecer el valor de ancho de trazo a 10. El evento mouseup cambia el valor de ancho de trazo a 5. Ten en mente que el evento mouseup tiene que ocurrir dentro del círculo mismo. Por ejemplo, el ancho de trazo no cambiará a 5 si presionas el botón del ratón dentro del círculo y luego lo sueltas solo después de que el cursor está fuera del círculo.

En el caso del círculo más grande, estamos usando el evento mousemove para cambiar su color fill. También estamos cambiando el cursor del círculo más grande usando stage.container().style.cursor siempre que el cursor se mueva dentro y fuera del círculo.

Please accept marketing cookies to load this content.

Una cosa importante que deberías tener en mente es que tienes que llamar al método draw() sobre la capa respectiva si los escuchadores de evento para cualquier forma resultan en un cambio con atributos como color de relleno, ancho de trazo, etc. De otro modo, los cambios no serán reflejados en el lienzo.

No tienes que enlazar un evento a la vez a una forma. También puedes pasar una cadena delimitada por espacio conteniendo múltiples tipos de evento al método on(). Esto enlazará todos los eventos listados en la cadena a esa forma particular.

Konva también soporta versiones móviles correspondientes a todos esos eventos. Por ejemplo, puedes registrar touchstart, touchmove, touchend, tap, dbltap, dragstart, dragmove, y dragend usando Konva en dispositivos móviles.

También puedes disparar cualquiera de esos eventos para una forma particular usando el método fire(). De manera similar, Konva te permite disparar eventos personalizados como throwStones.

Removiendo Escuchadores de Evento

Puedes remover cualquier escuchador de evento adjunto a una forma con la ayuda del método off() en Konva. Tienes que especificar el nombre de evento que no quieres escuchar.

También puedes crear múltiples enlaces de evento para una sola forma. Por ejemplo, digamos que tienes y círculo y quieres incrementar el radio del círculo cada vez que el cursor pasa sobre este, hasta cierto límite. También podrías querer cambiar el color de relleno del círculo en cada evento mouseover.

Una opción es hacer ambas tareas dentro de un solo escuchador de evento mouseover y dejar de actualizar el radio después. Otra opción es crear dos escuchadores de evento mouseover con diferentes nombres de espacio para identificarlos. De este modo, podrás incrementar el radio y cambiar el color de relleno de forma independiente.

1
circA.on("mouseover.radius", function() {
2
  var curRadius = circA.radius();
3
  if(curRadius < 150) {
4
    circA.radius(curRadius + 5);
5
    layerA.draw();
6
  } else {
7
    circA.off('mouseover.radius');
8
  }
9
});
10
11
circA.on("mouseover.fillcolor", function() {
12
  var h = Math.floor(Math.random()*360);
13
  var color = "hsl(" + h + ", 60%, 60%)";
14
  circA.fill(color);
15
  layerA.draw();
16
});

Deberías notar que he agregado layerA.draw() dentro de ambos escuchadores. Si no puedes agregarlo dentro del escuchador mouseover.fillcolor, el color dejará de actualizarse tan pronto como el radio sea 150.

Please accept marketing cookies to load this content.

En vez de remover un escuchador de evento a la vez, también puedes dejar de escuchar a todos los eventos atados a una forma usado el método setListening(). Puedes pasar true o false a este método para encender o apagar los escuchadores de eventos. Ten en mente que también tendrás que re-dibujar la gráfica de hito de la capa afectada llamando al método drawHit() justo después de que llames a setListening().

Delegación y Propagación de Evento

En vez de enlazar directamente a todas las formas presentes sobre una capa, también puedes enlazar un evento a la capa misma. Después de eso, puedes determinar cuál forma disparó el evento usando la propiedad target del objeto de evento. De este modo, Konva te permite delegar efectivamente eventos desde el padre a sus hijos.

Digamos que estás escuchando eventos de clic sobre un círculo dibujado en una capa en Konva. El mismo evento de clic se propaga al grupo contenedor así como a la capa contenedora. Esto podría o no ser el comportamiento deseado. Si quieres prevenir que el evento burbujee hacia adentro de una forma hasta la capa contenedora, puedes establecer la propiedad cancelBubble para el objeto de evento a true.

1
var canvasWidth = 600;
2
var canvasHeight = 400;
3
4
var stage = new Konva.Stage({
5
  container: "example",
6
  width: canvasWidth,
7
  height: canvasHeight
8
});
9
10
var layerA = new Konva.Layer();
11
12
var circA = new Konva.Circle({
13
  x: 300,
14
  y: 200,
15
  height: 100,
16
  fill: "orange",
17
  stroke: "black",
18
  name: "Orange Circle"
19
});
20
21
var starA = new Konva.Star({
22
  x: 125,
23
  y: 125,
24
  innerRadius: 25,
25
  outerRadius: 75,
26
  rotation: 90,
27
  fill: "blue",
28
  stroke: "black",
29
  name: "Blue Star"
30
});
31
32
var ringA = new Konva.Ring({
33
  x: 475,
34
  y: 275,
35
  innerRadius: 25,
36
  outerRadius: 75,
37
  fill: "brown",
38
  stroke: "black",
39
  name: "Brown Ring"
40
});
41
42
var textA = new Konva.Text({
43
  text: "",
44
  fontFamily: "Calibri",
45
  fontSize: 24,
46
  fill: "black",
47
  x: 10,
48
  y: 10
49
});
50
51
layerA.add(circA, starA, ringA, textA);
52
53
stage.add(layerA);
54
55
layerA.on("click", function(e) {
56
  var shapeName = e.target.attrs.name;
57
  textA.setText(shapeName);
58
  layerA.draw();
59
});

He usado la propiedad name para asignar un nombre a cada una de nuestras formas. El método setText() es después usado para cambiar el texto dentro de textA al nombre de la forma que acabamos de dar clic.

Please accept marketing cookies to load this content.

Regiones de Toque Personalizadas

En el ejemplo de arriba, el anillo registró un clic sobre él cuando el clic ocurrió entre el círculo interior y exterior. ¿Qué pasa si quisieras registrar el clic dentro del círculo pequeño también? Konva te permite definir regiones de toque personalizadas usando la propiedad hitFunc. Esta propiedad acepta una función como su valor, y esta función es usada para dibujar la región personalizada.

El siguiente ejemplo te muestra cómo crear regiones de toque personalizadas. Ahora deberías poder dar clic en el área entre los picos de la estrella y aún registrar un clic. Con la ayuda de las regiones de toque personalizadas, puedes asegurar que los usuarios no tienen que dar clic en ubicaciones exactas para registrar un evento de clic. Esto puede resultar en una mejor experiencia de usuario cuando se trata con formas más pequeñas o complejas.

1
var starA = new Konva.Star({
2
  x: 125,
3
  y: 125,
4
  innerRadius: 25,
5
  outerRadius: 75,
6
  rotation: 90,
7
  fill: "blue",
8
  stroke: "black",
9
  name: "Blue Star",
10
  hitFunc: function(context) {
11
    context.beginPath();
12
    context.arc(0, 0, this.getOuterRadius(), 0, Math.PI * 2, true);
13
    context.closePath();
14
    context.fillStrokeShape(this);
15
  }
16
});
17
18
var ringA = new Konva.Ring({
19
  x: 475,
20
  y: 275,
21
  innerRadius: 25,
22
  outerRadius: 75,
23
  fill: "brown",
24
  stroke: "black",
25
  name: "Brown Ring",
26
  hitFunc: function(context) {
27
    context.beginPath();
28
    context.arc(0, 0, this.getOuterRadius(), 0, Math.PI * 2, true);
29
    context.closePath();
30
    context.fillStrokeShape(this);
31
  }
32
});

Please accept marketing cookies to load this content.

Ideas Finales

En este tutorial. Hemos cubierto diferentes eventos de móvil y escritorio que puedes enlazar a cualquier forma en Konva. Puedes adjuntar estos eventos uno a la vez o muchos de ellos al mismo tiempo. Konva también te permite disparar tus propios eventos personalizados con programación usando el método fire(). La última sección de este turorial te mostró cómo definir tus propias regiones de toque para poder detectar toques sobre un área que podría ser más grande o pequeña que la forma original.

Combinando el conocimiento de este tutorial con otros en la serie, ahora deberías poder dibujar una variedad de formas sobre el lienzo y permitir a tus usuarios interactuar con ellos.

Si tienes cualquier pregunta relacionada con este tutorial, siéntete libre de hacérmelo saber en los comentarios.