Maison  >  Article  >  interface Web  >  Implémenter le code objet en mouvement via JavaScript

Implémenter le code objet en mouvement via JavaScript

零下一度
零下一度original
2017-04-17 17:56:452611parcourir

L'un des principaux objectifs de l'animation interactive est de créer une expérience utilisateur fluide, dans laquelle la plupart des interactions de l'utilisateur s'effectuent via la souris et l'écran tactile.

Dans cet article de blog, j'aimerais partager quelques utilisations courantes de JS pour déplacer des objets, y compris les effets de glisser-lancer.

1. L'utilisation d'événements de souris

peut décomposer un événement de clic de souris en deux événements : un événement de souris enfoncée et un événement de bouton relevé. Généralement, ces deux événements se produisent simultanément. Cependant, parfois, après avoir appuyé sur la souris, la souris bouge pendant un certain temps avant d'apparaître. Cette opération est appelée glisser, c'est-à-dire appuyer, déplacer et relâcher.

Dans l'animation du canevas, les événements de souris ne peuvent être capturés que par les éléments du canevas sur l'arborescence HTML DOM. Par conséquent, nous devons calculer manuellement où l'événement de souris se produit sur le canevas et déterminer s'il se produit dans quel dessin sur le canevas. objet de toile. Les événements de souris qui nécessitent une attention particulière sont : mousedown, mousemove et mouseup. Pour des détails spécifiques, veuillez vous référer à mon article de blog associé "Explication détaillée de l'animation JavaScript (1) - Boucle et surveillance des événements".

2. Utilisation des événements tactiles

Avec la popularité des appareils à écran tactile, nous devrons probablement capturer les événements tactiles de l'utilisateur dans des animations. Bien qu'un écran tactile et une souris soient des appareils différents, heureusement, la capture d'événements tactiles dans l'arborescence DOM n'est pas si différente de la capture d'événements de souris.

Les événements tactiles correspondant aux événements de souris mousedown, mousemove et mouseup sont respectivement touchstart, touchend et touchmove.

Une grande différence entre l'utilisation des doigts et de la souris est que la souris apparaît toujours sur l'écran, mais les doigts ne sont pas toujours en contact. Une approche courante consiste à introduire un attribut personnalisé isPressed pour nous dire si un doigt touche l'écran. Pour des détails spécifiques, veuillez vous référer à mon article de blog associé "Explication détaillée de l'animation JavaScript (1) - Boucle et surveillance des événements".

3. Événement Drag

L'événement Drag contient trois sous-événements : appuyer sur la souris, déplacer et relâcher. En mettant continuellement à jour la position des coordonnées de l'objet pour suivre la position du pointeur de la souris, vous pouvez faire glisser l'objet sur l'élément de canevas. De plus, un attribut personnalisé isPressed est nécessaire pour indiquer si la souris est actuellement enfoncée. La valeur par défaut est false, ce qui signifie que la souris est à l'état haut. Le code d'implémentation comprend le processus suivant :

1. Capturez l'événement mousedown et déterminez si la souris actuelle se trouve dans l'objet. Lorsque la souris est enfoncée dans l'objet, set isPressed = true;

2. Capturez l'événement mousemove, déterminez dans le gestionnaire quand isPressed = true et mettez à jour en permanence la position des coordonnées de l'objet pour qu'il suive la position. position du pointeur de la souris pour simuler l'effet de glissement de la souris ;

3. Capturez l'événement mouseup et définissez isPressed sur false

Le code JavaScript est le suivant :
<canvas id="canvas" width="400" height="400"></canvas>

Cependant, cet exemple comporte des bugs ! Vous constaterez bientôt que lorsque vous faites glisser, le centre de la balle se trouve à la position de la souris. Surtout lorsque la souris clique sur le bord de la balle, vous verrez que le centre de la balle saute soudainement à la position du curseur de la souris. Sur. Évidemment, cela semble un peu brusque.
// 创建画球函数
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;
}

Nous pouvons apporter une légère amélioration :

Enregistrez le décalage entre la position actuelle de la souris et le point central de la balle lorsque la souris est enfoncée

Lorsque la souris bouge, soustrayez le décalage enregistré lorsque la souris est enfoncée de la position actuelle de la souris
// 记录鼠标按下时,鼠标与小球圆心的偏移量
dx = mouse.x - ball.x;
dy = mouse.y - ball.y;

4. Lancer event
ball.x = mouse.x - dx;
ball.y = mouse.y - dy;

Comment exprimer le lancer en animation ? Utilisez la souris pour sélectionner un objet et faites-le glisser pour le déplacer dans une certaine direction. Après avoir relâché la souris, l'objet continue de se déplacer dans la direction déplacée.

Lors du lancement d'un objet, le vecteur vitesse de l'objet doit être calculé pendant le processus de glissement, et ce vecteur vitesse doit être attribué à l'objet lors du relâchement de l'objet. En fait, le processus de calcul du vecteur vitesse d’un objet lors du déplacement est exactement le contraire de l’application du vecteur vitesse à l’objet. Lors de l'application d'un vecteur vitesse à un objet, la vitesse est ajoutée à la position d'origine de l'objet pour calculer la nouvelle position de l'objet. Cette formule peut s'écrire :

ancienne position + vecteur vitesse = nouvelle position

. , c'est-à-dire

Vecteur vitesse = nouvelle position – ancienne position

. Afin d'implémenter le comportement de lancement, certaines modifications doivent être apportées au code précédent. Tout d'abord, vérifiez si la souris est enfoncée. Si vous appuyez dessus, utilisez les variables oldX et oldY pour enregistrer les anciennes positions de coordonnées x et y de la balle et mettez à jour la vitesse de déplacement de la balle. Le code JavaScript spécifique est implémenté comme suit :

// 创建画球函数
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);
}

Il y a encore quelques bugs dans le jugement des limites de cette démo, qui sera réglé dans quelques jours.

5. Résumé

Les événements de mouvement d'objet peuvent avoir de nombreuses formes de mouvement total, mais ils peuvent tous être décomposés en trois événements distincts pour le contrôle : appuyer, déplacer, relâcher. , qui correspondent respectivement à mousedown, mousemove et mouseup dans les événements de souris, et à touchstart, touchmove et touchend respectivement dans les événements tactiles. En mettant constamment à jour la position des coordonnées de l'objet afin qu'il suive la position du pointeur de la souris, l'effet de glisser-lancer sur l'élément de canevas peut être obtenu.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn