Introduction to HTML5 Canvas event processing, html5canvas
This article mainly introduces HTML5 Canvas event processing. This article describes Canvas restrictions, binding events to Canvas elements, the isPointInPath method, cyclic repainting, and event bubbling, for more information, see
DOM is a very important part of the Web Front-end field. It is used not only for processing HTML elements, but also for Graphic programming. For example, in SVG drawing, all kinds of images are inserted into the page in the form of DOM nodes, which means that you can use the DOM method to operate the graphics. For example, if there is a <path id = "p1"> element, you can directly add the click Event $ ('# p1'). click (function () {…}) with jquery (){...}) ". However, this DOM processing method is no longer applicable in HTML5 Canvas. Canvas uses another mechanism. No matter how many images are drawn on the Canvas, Canvas is a whole, the image itself is actually a part of the Canvas and cannot be obtained independently. Therefore, JavaScript events cannot be directly added to a graph.
Canvas restrictions
In the Canvas, all images are drawn on frames. The painting method does not output the drawn graphic elements as a return value, and js cannot obtain the drawn graphic elements. For example:
The Code is as follows:
Cvs = document. getElementById ('mycanvas ');
Ctx = canvas. getContext ('2d ');
TheRect = ctx. rect (10, 10,100,100 );
Ctx. stroke ();
Console. log (theRect); // undefined
This Code draws a rectangle in the canvas label. First, we can see that the rect Method for drawing the image has no return value. If you open the developer tool of the browser, you can also see that no content is added inside the canvas tag, but the canvas Element obtained in js and the current context are displayed, there is no new graphic content.
Therefore, common dom methods on the front end are not applicable in canvas. For example, if you click the rectangle in the Canvas above, the entire Canvas element is actually clicked.
Bind events to the Canvas Element
Because the event can only reach the Canvas Element layer, you need to add code to identify which image is clicked inside the Canvas for further exploration. The basic idea is to bind an event to the Canvas element. when an event occurs, check the location of the event object and then check which images overwrite the event. For example, a rectangle is drawn in the above example, which covers the range of X axis 10-110 and Y axis 10. As long as the mouse clicks in this range, it can be regarded as clicking the rectangle, it can also manually trigger the click event to be processed by the rectangle. The idea is actually relatively simple, but the implementation is a little complicated. Not only must we consider the efficiency of this judgment process, but in some cases, we also need to re-judge the event type and set a new capture and bubble mechanism inside the Canvas.
The first thing to do is to bind an event to the Canvas element. For example, to bind a click event to a drawing inside the Canvas, you must use the Canvas Element to proxy the event:
The Code is as follows:
Cvs = document. getElementById ('mycanvas ');
Cvs. addEventListener ('click', function (e ){
//...
}, False );
Next, you need to determine the location of the event object. The layerX and layerY attributes of event object e represent the coordinates in the Canvas internal coordinate system. However, this attribute is not supported by Opera and Safari is also intended to be removed. Therefore, we need to write some compatible methods:
The Code is as follows:
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 };
}
// Note: to use the above function, set the position of the Canvas element to absolute.
Now that we have the coordinates of the event object, we need to determine which images in the Canvas overwrite the coordinates.
IsPointInPath Method
The isPointInPath method of Canvas can be used to determine whether the current context graph overwrites a coordinate. For example:
The Code is as follows:
Cvs = document. getElementById ('mycanvas ');
Ctx = canvas. getContext ('2d ');
Ctx. rect (10, 10,100,100 );
Ctx. stroke ();
Ctx. isPointInPath (50, 50); // true
Ctx. isPointInPath (5, 5); // false
Next, add an event judgment to determine whether a click event is on the rectangle:
The Code is as follows:
Cvs. addEventListener ('click', function (e ){
P = getEventPosition (e );
If (ctx. isPointInPath (p. x, p. y )){
// Click the rectangle.
}
}, False );
The above is the basic method for handling Canvas events, but the above Code is still limited. Because the isPointInPath method only determines the path in the current context, when multiple images have been drawn in the Canvas, events can only be judged in the context of the last graph, for example:
The Code is as follows:
Cvs = document. getElementById ('mycanvas ');
Ctx = canvas. getContext ('2d ');
Ctx. beginPath ();
Ctx. rect (10, 10,100,100 );
Ctx. stroke ();
Ctx. isPointInPath (20, 20); // true
Ctx. beginPath ();
Ctx. rect (1, 110,110,100,100 );
Ctx. stroke ();
Ctx. isPointInPath (150,150); // true
Ctx. isPointInPath (20, 20); // false
From the code above, we can see that the isPointInPath method can only identify the graph path in the current context, but the previously drawn path cannot be traced back. The solution to this problem is: when a click event occurs, re-draw all the images and use the isPointInPath method to determine whether the event coordinates are within the coverage range of the image.
Loop repainting and event bubbling
To achieve cyclic re-painting, we need to save the basic parameters of the image in advance:
The Code is as follows:
Arr = [
{X: 10, y: 10, width: 100, height: 100 },
{X: 110, y: 110, width: 100, height: 100}
];
Cvs = document. getElementById ('mycanvas ');
Ctx = canvas. getContext ('2d ');
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 ();
});
}
The above code saves the basic parameters of the two rectangles in advance. Each call to the draw method will call these basic parameters cyclically to draw two rectangles. The clearRect method is also used to clear the canvas during re-painting. The next step is to add an event proxy and use the isPointInPath method for each context during re-painting:
The Code is as follows:
Cvs. addEventListener ('click', function (e ){
P = getEventPosition (e );
Draw (p );
}, False );
When an event occurs, the coordinates of the event object are transmitted to the draw method for processing. Here we also need to make some minor changes to the draw method:
The Code is as follows:
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 )){
// If the event coordinates are input, use isPointInPath to judge
// If the current environment overwrites the coordinates, place the index value of the current environment in the array
Who. push (I );
}
});
// Based on the index value in the array, you can find the corresponding element in the arr array.
Return who;
}
In the above Code, when a click event occurs, the draw method performs a re-painting and checks whether the event coordinates are overwritten by each image during the re-painting process. If the result is true, click the graph, put the index value of the graph into an array, and use the array as the return value of the draw method. In this processing mechanism, if there are N images in the Canvas, some of them overlap, and the click event happens in this overlapping area, then there will be N members in the returned array of the draw method. Slave get, while other members are the nodes passed in during the bubble process. Of course, this is only the simplest method. If you want to simulate DOM processing, you also need to set a parent-child relationship for the graph.
The above is the basic method for handling Canvas events. In actual use, you still need to spend some time to handle how to cache graphic parameters, how to redraw cyclically, and how to handle event bubbles. In addition, click is a relatively well-handled event. The relatively troublesome events are mouseover, mouseout, and mousemove. As the mouse enters the Canvas Element, all the events that occur are mousemove events, therefore, if you want to set a single mouseover or mouseout for a graphic, you also need to record the mouse movement route and set the inbound and outbound statuses for the graphic. As the processing steps become complex, you must pay more attention to performance issues.