DOM is a very important part of the Web front-end field. DOM is used not only when processing HTML elements, but also in graphic programming. For example, in SVG drawing, various graphics are inserted into the page in the form of DOM nodes, which means that graphics can be manipulated using DOM methods. For example, if there is an element, you can directly use jquery to add a click event $('#p1').click(function(){…})". However, this DOM processing method is no longer applicable in HTML5 Canvas. Canvas uses It is another set of mechanisms. No matter how many graphics are drawn on Canvas, Canvas is a whole. The graphics themselves are actually part of Canvas and cannot be obtained separately, so it is impossible to directly add JavaScript events to a certain graphic.
Canvas. Limitations
In Canvas, all graphics are drawn on the frame. The drawing method will 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 tag. First of all, you can see that the rect method for drawing graphics has no return value. It can be seen that no content is added inside the canvas tag, and the canvas element and the current context obtained in js do not have any content indicating the new graphics
So, the dom methods commonly used in the front end are not used in canvas. Applicable. For example, when you click on the rectangle in the Canvas above, you actually click on the entire Canvas element.
Binding events to the Canvas element
Since the event can only reach the Canvas element level, if you want to go further, identify the click occurrence. Which graphic inside the Canvas needs to be added for processing. The basic idea is: bind an event to the Canvas element, when the event occurs, check the position of the event object, and then check which graphics cover the position, such as the above. In the example, a rectangle is drawn, which covers the range of 10-110 on the x-axis and 10-110 on the y-axis. As long as the mouse is clicked in this range, it can be regarded as clicking on the rectangle, and the rectangle can be manually triggered to be processed. Click event. The idea is actually relatively simple, but the implementation is still a bit complicated. Not only must the efficiency of this judgment process be considered, but also the event type needs to be re-judged in some places, and the capture and bubbling mechanism inside the Canvas must be redefined.
The first thing to do is to bind events to the Canvas element. For example, if you want to bind a click event to a graphic inside the Canvas, you need to proxy the event through the Canvas element:
The code is as follows:
cvs = document.getElementById('mycanvas ');
cvs.addEventListener('click', function(e){
//...
}, false);
Next we need to determine the location where the event object occurs, the layerX and layerX of the event object e The layerY attribute represents the coordinates in the Canvas internal coordinate system. However, Opera does not support this attribute, and Safari plans to remove it, so we need to make some compatible writing 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
.offsetX;
y = ev.offsetY;
}
return {x: .
Now that we have the coordinate position of the event object, we need to determine which graphics in the Canvas cover this coordinate.
isPointInPath method
Canvas's isPointInPath method can determine whether the current context graphic covers a certain 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 occurs on the rectangle:
The code is as follows:
cvs.addEventListener('click', function(e){
p = getEventPosition(e);
if(ctx.isPointInPath(p.x, p.y)){
//The rectangle was clicked
}
}, false);
The above is the basic method of handling Canvas events, but The above code still has limitations. Since the isPointInPath method only determines the path in the current context, when multiple graphics have been drawn in the Canvas, the event can only be determined based on the context of the last graphic. 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(110, 110, 100, 100);
ctx.stroke( ; The graphic path, and the previously drawn path cannot be judged retrospectively. The solution to this problem is: when a click event occurs, redraw all graphics, and use the isPointInPath method for each drawing to determine whether the event coordinates are within the coverage of the graphics.
Loop redrawing and event bubbling
In order to implement loop redrawing, the basic parameters of the graphics must be saved 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 is in advance Save the basic parameters of the two rectangles. Each time the draw method is called, these basic parameters will be called cyclically to draw the two rectangles. The clearRect method is also used here to clear the canvas when redrawing. The next thing to do is to add event delegates and use the isPointInPath method for each context when redrawing:
The code is as follows:
cvs.addEventListener('click', function(e){
p = getEventPosition( e);
draw(p);
}, false);
When the event occurs, the coordinates of the event object are passed to the draw method for processing. Some small changes need to be made to the draw method here:
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 passed in, use isPointInPath to judge
//If the current environment covers the coordinates, change the index value of the current environment Put it in the array
who.push(i);
}
});
//According to the index value in the array, you can find the corresponding element in the arr array.
return who;
}
In the above code, when the click event occurs, the draw method will perform a redraw, and during the redraw process, check whether each graphic covers the event coordinates. If the judgment is true, it will be regarded as In order to click on the graphic, put the index value of the graphic into the array, and finally use the array as the return value of the draw method. Under this processing mechanism, if there are N graphics in the Canvas, part of them overlaps, and the click event happens to occur in this overlapping area, then there will be N members in the return array of the draw method. At this time, it is a bit similar to the situation of event bubbling. The last member of the array is at the top of the Canvas, and the first member is at the bottom. We can think of the top member as e.target, while the other members are e.target. The node passed to during the bubble process. Of course, this is just the simplest processing method. If you really want to simulate DOM processing, you need to set a parent-child relationship for the graphics.
The above is the basic method of Canvas event handling. In actual application, how to cache graphics parameters, how to perform loop redrawing, and how to handle event bubbling all need to be dealt with according to the actual situation. In addition, click is an event that is relatively easy to handle. The relatively troublesome events are mouSEOver, mouseout and mousemove. Since once the mouse enters the Canvas element, the mousemove event always occurs, so if you want to set mouseover or mouseout separately for a certain graphic , you also need to record the route of the mouse movement and set the entry and exit status for the graphics. As the processing steps become more complex, increased attention must be paid to performance issues.
The above is the introduction to event processing of HTML5 Canvas. For more related articles, please pay attention to the PHP Chinese website (www.php.cn)!