To keep track of what is being drawn, many applications, such as drawing applications, computer-aided design systems (CAD systems), and games, maintain a list of currently displayed objects. Typically, these applications allow users to manipulate objects currently displayed on the screen. For example, in a CAD application, we can select, move, zoom, etc. elements in the design
-"HTML5 Canvas Core Technology"
The same is true 实现拖拽
in Canvas. Canvas provides an API called isPointInPath(x, y)
to determine whether 点(x, y)
is in the path. Returns true if it is within the path. So we can have the following ideas:
Maintain an 数组
that can describe each path, and use ispointInPath(x, y)
to determine whether the clicked position is in a certain path. If it is in this path, select this path, perform operations (move, zoom, etc.), and then draw the graphics
In this article, I use 多边形拖拽为例进行说明
. The demo is as follows (the reason behind the imprint is the screen recording software: japanese_ogre:):
CodePen opens
How to draw polygons in Demo has been summarized before, so I won’t go into details again: ghost:: Canvas polygon drawing
Explanation of ideasThe figure below gives a rough description and pseudo code. The idea is not difficult, but there are some details that need to be dealt with.
The code structure is listed here and its ideas are marked. More detailed code comments are in CodePen.
Because this article focuses on drag, there will be less description of the drawing part.
//Draw polygon path function function drawPolygonPath//Polygon class definition class Polygon{ ...}//Return the position in the canvas according to the click event function positoinInCanvas//Get the straight-line distance between two points function getDistance//In the beginning stage, record the drag Drag object canvas.onmousedown//Drag phase, draw path, stroke canvas.onmousemove//End phase, update drag object position canvas.onmouseupDescription of key parts
Next, start processing the key parts and details of the code
How to maintain an array of drag objectsDuring program initialization, we define a polygonArray array
polygonArray = []
Every time a new polygon is drawn, a new polygon object will be pushed into the array for maintenance.
const polygon = new Polygon(mouseStart.get('x'), mouseStart.get('y'), sideNum, radius);polygonArray.push(polygon);//Record path object
In subsequent click operations, it is necessary to determine whether the click position is in the path based on the corresponding information.
How to select the object to drag when clicking First, get the corresponding position canvas中
when clicked. My code uses mouseStart
to record x
and y
Then traverse polygon
in polygonArray
, call polygon.createPath()
during the traversal, and use isPointInPath()
to determine whether there is a path at the clicked position. If so, draggingPolygon = polygon
ends the function.
const pos = positionInCanvas(e, canvasLeft, canvasTop);//Get the pixel position in canvas//Record the mouse starting point smouseStart.set('x', pos.x);mouseStart.set('y', pos. y);...for (let polygon of polygonArray) { polygon.createPath(); if (ctx.isPointInPath(mouseStart.get('x'), mouseStart.get('y'))) { draggingPolygon = polygon; return; } }Calculation when dragging
This part must be fully understood. It is recommended that you debug based on the two console.log(draggingPolygon)
and code in the Demo, because we are in the mousemove
stage, and the functions are triggered very frequently at this stage.
I try to express it clearly in words
First, calculate the distance from mouseStart
when move
, which is recorded as diff. There is offsetX
on the x-axis and offsetY
on the y-axis.
const pos = positionInCanvas(e, canvasLeft, canvasTop), diff = new Map([ ['offsetX', pos.x - mouseStart.get('x')], ['offsetY', pos.y - mouseStart.get( 'y')] ]);
Then record centerX
and centerY
of the current drag object, recorded as temp
let tempCenterX = draggingPolygon.centerX, tempCenterY = draggingPolygon.centerY;
This is the difficult point to understand. Why should we record it? Keep reading, you will use it later.
Set the new center position of draggingPolygon according to the offset in diff
draggingPolygon.centerX += diff.get('offsetX'); draggingPolygon.centerY += diff.get('offsetY');
Then clear the canvas and draw new paths and strokes
ctx.clearRect(0, 0, canvas.width, canvas.height);for (let polygon of polygonArray) { drawPolygonPath(polygon.sideNum, polygon.radius, polygon.centerX, polygon.centerY, ctx); ctx.stroke( );}
Finally, tempCenterX
and tempCenterY
mentioned above are used:
draggingPolygon.centerX = tempCenterX; draggingPolygon.centerY = tempCenterY;
Why do we need to do this?
Because our dragging is 基于多边形的原位置
, and mousemove
stage 不能确定函数的最终位置
. If there is no recovery at this time, 漂移
will occur. I commented out these two lines of code, and the effect is as follows:
If I didn’t make it clear, I recommend everyone to modify and debug the code.
Processing after dragging After dragging is completed, it is in the mouseup
stage. At this time, we have determined the final position of dragginPolygon, just update it, and finally set it to null to exclude 在没有拖拽多边形情况下,鼠标在画布上移动触发对应代码
const pos = positionInCanvas(e, canvasLeft, canvasTop), offsetMap = new Map([ ['offsetX', pos.x - mouseStart.get('x')], ['offsetY', pos.y - mouseStart.get( 'y')] ]); draggingPolygon.centerX += offsetMap.get('offsetX'); draggingPolygon.centerY += offsetMap.get('offsetY'); draggingPolygon = null;Conclusion
In fact, it is not difficult to implement this function. The key is to understand a concept: tracking is achieved by maintaining a list of currently displayed objects and making judgments with isPointInPath.
Finally, welcome everyone to exchange and learn
References"HTML5 Canvas Core Technology"
The above is the entire content of this article. I hope it will be helpful to everyone’s study. I also hope everyone will support VeVb Wulin Network.