Home > Article > Web Front-end > Implement moving object code through JavaScript
A main goal of interactive animation is to create a smooth user experience, where most user interaction is achieved through the mouse and touch screen.
In this blog post, I want to share some common uses of JS for moving objects, including dragging and throwing effects.
You can decompose a mouse click event into two events: a mouse press event and a button pop-up event. Typically these two events occur simultaneously. However, sometimes after the mouse is pressed, the mouse will move for a while before popping up. This operation is called dragging, that is, pressing, moving, and releasing.
In canvas animation, mouse events can only be captured by canvas elements on the HTML DOM tree. Therefore, we need to manually calculate where the mouse event occurs on the canvas and determine whether it occurs in which Draw onto the canvas object. The mouse events that need attention are: mousedown, mousemove and mouseup. For specific details, please refer to my related blog post "Detailed Explanation of JavaScript Animation (1) - Looping and Event Monitoring".
With the popularity of touch screen devices, we are likely to need to capture the user's touch events in animations. Although a touch screen and a mouse are different devices, fortunately, capturing touch events in the DOM tree is not that different from capturing mouse events.
The touch events corresponding to the mouse events mousedown, mousemove and mouseup are touchstart, touchend and touchmove respectively.
A big difference between using fingers and a mouse is that the mouse always appears on the screen, but the fingers are not always in touch. A common approach is to introduce a custom attribute isPressed to tell us whether there is a finger touching the screen. For specific details, please refer to my related blog post "Detailed Explanation of JavaScript Animation (1) - Looping and Event Monitoring".
The drag event contains three sub-events: mouse press, move, and release. By continuously updating the coordinate position of the object to follow the position of the mouse pointer, you can drag the object on the canvas element. In addition, a custom attribute isPressed is needed to indicate whether the mouse is currently pressed. The default value is false, which means the mouse is in the up state. The implementation code includes the following process:
1. Capture the mousedown event and determine whether the current mouse is within the object. When the mouse is pressed within the object, set isPressed = true;
2. Capture the mousemove event, determine in the handler when isPressed = true, and continuously update the coordinate position of the object to make it follow the mouse pointer. position to simulate the mouse dragging effect;
3. Capture the mouseup event and set isPressed to false;
HTML code is as follows:
<canvas id="canvas" width="400" height="400"></canvas>
The JavaScript code is as follows:
// 创建画球函数 function Ball() { this.x = 0; this.y = 0; this.radius = 20; this.fillStyle = "#f85455"; this.draw = function(cxt) { cxt.fillStyle = this.fillStyle; cxt.beginPath(); cxt.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, true); cxt.closePath(); cxt.fill(); } } // 获得当前鼠标位置 function getMouse(ev) { var mouse = { x: 0, y: 0 }; var event = ev || window.event; if(event.pageX || event.pageY) { x = event.x; y = event.y; }else { var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft; var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; x = event.clientX + scrollLeft; y = event.clientY + scrollTop; } mouse.x = x; mouse.y = y; return mouse; } var canvas = document.getElementById("canvas"), context = canvas.getContext("2d"), ball = new Ball(), mouse = {x: 0, y: 0}, isPressed = false; ball.x = 20; ball.y = 20; // 渲染小球 ball.draw(context); // 小球拖拽事件 canvas.addEventListener("mousedown", mouseDown, false); canvas.addEventListener("mousemove", mouseMove, false); canvas.addEventListener("mouseup", mouseUp, false); function mouseDown(ev) { // 判断当前鼠标是否在小球内 mouse = getMouse(ev); if(Math.pow(mouse.x - ball.x, 2) + Math.pow(mouse.y - ball.y, 2) <= Math.pow(ball.radius, 2)) { isPressed = true; } } function mouseMove(ev) { if(isPressed) { mouse = getMouse(ev); ball.x = mouse.x; ball.y = mouse.y; context.clearRect(0, 0, canvas.width, canvas.height); ball.draw(context); } } function mouseUp(ev) { // 标示鼠标弹起事件 isPressed = false; }
However, this example has bugs! You will soon find that when dragging, the center of the ball is at the mouse position. Especially when the mouse clicks on the edge of the ball, you will see that the center of the ball suddenly jumps to the position of the mouse cursor. On. Obviously, this seems a bit abrupt.
We can make a slight improvement:
Record the offset between the current mouse position and the center point of the ball when the mouse is pressed;
// 记录鼠标按下时,鼠标与小球圆心的偏移量 dx = mouse.x - ball.x; dy = mouse.y - ball.y;
When the mouse moves, subtract the offset recorded when the mouse is pressed from the current position of the mouse
ball.x = mouse.x - dx; ball.y = mouse.y - dy;
How to express throwing in animation? Use the mouse to select an object and drag it to move in a certain direction. After releasing the mouse, the object continues to move in the dragged direction.
When throwing an object, the velocity vector of the object must be calculated during the dragging process, and this velocity vector must be assigned to the object when the object is released. In fact, the process of calculating the velocity vector of an object while dragging is exactly the opposite of applying the velocity vector to the object. When applying a velocity vector to an object, the velocity is added to the original position of the object to calculate the new position of the object. This formula can be written as: old position + velocity vector = new position, that is Velocity vector = new position – old position.
In order to implement the throwing behavior, some changes need to be made to the previous code. First, check whether the mouse is pressed. If it is pressed, use the oldX and oldY variables to save the old x and y coordinate positions of the ball, and update the dragging speed of the ball.
The specific JavaScript code is implemented as follows:
// 创建画球函数 function Ball() { this.x = 0; this.y = 0; this.radius = 20; this.fillStyle = "#f85455"; this.draw = function(cxt) { cxt.fillStyle = this.fillStyle; cxt.beginPath(); cxt.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, true); cxt.closePath(); cxt.fill(); } } // 获得当前鼠标位置 function getMouse(ev) { var mouse = { x: 0, y: 0 }; var event = ev || window.event; if(event.pageX || event.pageY) { x = event.x; y = event.y; }else { var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft; var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; x = event.clientX + scrollLeft; y = event.clientY + scrollTop; } mouse.x = x; mouse.y = y; return mouse; } var canvas = document.getElementById("canvas"), context = canvas.getContext("2d"), ball = new Ball(), mouse = {x: 0, y: 0}, isPressed = false, oldX = 0, oldY = 0, currentX = 0, currentY = 0, vx = 0, vy = 0; ball.x = 200; ball.y = 200; // 声明鼠标按下时,鼠标与小球圆心的距离 var dx = 0, dy = 0; // 渲染小球 ball.draw(context); // 小球拖拽事件 canvas.addEventListener("mousedown", mouseDown, false); canvas.addEventListener("mousemove", mouseMove, false); canvas.addEventListener("mouseup", mouseUp, false); function mouseDown(ev) { // 判断当前鼠标是否在小球内 mouse = getMouse(ev); if(Math.pow(mouse.x - ball.x, 2) + Math.pow(mouse.y - ball.y, 2) <= Math.pow(ball.radius, 2)) { isPressed = true; // 记录鼠标按下时,鼠标与小球圆心的距离 dx = mouse.x - ball.x; dy = mouse.y - ball.y; // 获得小球拖拽前的位置 mouse = getMouse(ev); oldX = mouse.x; oldY = mouse.y; } } function mouseMove(ev) { if(isPressed) { mouse = getMouse(ev); ball.x = mouse.x - dx; ball.y = mouse.y - dy; context.clearRect(0, 0, canvas.width, canvas.height); ball.draw(context); } } function mouseUp(ev) { // 标示鼠标弹起事件 isPressed = false; // 把鼠标与圆心的距离位置恢复初始值 dx = 0; dy = 0; // 获得小球拖拽后的位置 mouse = getMouse(ev); currentX = mouse.x; currentY = mouse.y; // 更新速度向量:速度向量 = 新的位置 - 旧的位置 vx = (currentX - oldX) * 0.05; vy = (currentY - oldY) * 0.05; drawFrame(); } // 缓动动画 function drawFrame() { animRequest = window.requestAnimationFrame(drawFrame, canvas); context.clearRect(0, 0, canvas.width, canvas.height); if(ball.x >= canvas.width - 30 || ball.x <= 30 || ball.y >= canvas.height - 30 || ball.y <= 30) { window.cancelAnimationFrame(animRequest); } ball.x += vx; ball.y += vy; ball.draw(context); }
There are still some bugs in the boundary judgment of this Demo, which will be fixed in a few days.
Object movement events can have many forms of total movement, but they can all be decomposed into three separate events for control: press, move, release , which correspond to mousedown, mousemove and mouseup respectively in mouse events, and touchstart, touchmove and touchend respectively in touch events. By constantly updating the coordinate position of the object so that it follows the position of the mouse pointer, the effect of dragging and throwing on the canvas element can be achieved.
The above is the detailed content of Implement moving object code through JavaScript. For more information, please follow other related articles on the PHP Chinese website!