【问题标题】:How do I stop a canvas animation when the same function is called again?再次调用相同的函数时如何停止画布动画?
【发布时间】:2020-09-05 12:38:33
【问题描述】:

我目前正在编写一个网站,点击导航链接后,HTML 画布会在相关内容框上画一条线(我在这里使用了 markE 的精彩回答 https://stackoverflow.com/a/23941786 作为动画教程)。我正在为这些线条制作动画,我遇到了以下问题:

如何在点击另一个链接时阻止第一个动画完成?

我已经尝试在几次迭代中同时创建一个标志和 cancelAnimationFrame,但没有任何乐趣。

这是一些简化的代码,目前使用了一个标志:

HTML

<div class="container">
    <nav>
        <ul>
            <li>
                <a href="#about" id="about" onclick="draw(this.id);">About</a>
            </li>
            <li>
                <a href="#contact" id="contact" onclick="draw(this.id);">Work</a>
            </li>
        </ul>
    </nav>
</div>
<canvas id="canvas"  width="500" height="500"></canvas>

JavaScript

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var isRunning = false;
function draw(contentId) {
    if (isRunning) return;
    isRunning = true;
    var t = 1;
    var vertices = [];
    function calcWaypoints(vertices) {
        var waypoints = [];
        for (var i = 1; i < vertices.length; i++) {
            var pt0 = vertices[i - 1];
            var pt1 = vertices[i];
            var dx = pt1.x - pt0.x;
            var dy = pt1.y - pt0.y;
            for (var j = 0; j < 100; j++) {
                var x = pt0.x + dx * j / 100;
                var y = pt0.y + dy * j / 100;
                waypoints.push({
                    x: x,
                    y: y
                });
            }
        }
        return (waypoints);
    }

    function animate() {
        if (t < points.length - 1) {
            window.requestAnimationFrame(animate);
        }

        ctx.beginPath();
        ctx.moveTo(points[t - 1].x, points[t - 1].y);
        ctx.lineTo(points[t].x, points[t].y);
        ctx.stroke();
        t++;
        isRunning = false;
    }

// Clear the canvas before drawing
    ctx.clearRect(0, 0, canvas.width, canvas.height);
// Assign coordinates
    if (contentId == 'about') {
        vertices.push({x: 50, y: 0}, {x: 50, y: 50});
        vertices.push({x: 40, y: 60}, {x: 0, y: 60});
// Animate lines
        ctx.lineCap = "round";
        ctx.lineWidth = border;
        ctx.strokeStyle = "green";
        var points = calcWaypoints(vertices);
        animate(points);
    }
    if (contentId == 'contact') {
        vertices.push({x: 150, y: 0}, {x: 150, y: 50});
        vertices.push({x: 160, y: 60}, {x: 300, y: 60});
        vertices.push({x: 300, y: 70}, {x: 310, y: 70});
        ctx.lineCap = "round";
        ctx.lineWidth = border;
        ctx.strokeStyle = "green";
        var points = calcWaypoints(vertices);
        animate(points);
    }
}

重申一下,以防我不清楚:当我点击“关于”然后立即点击“联系”时,我希望在我第一次点击“关于”时初始化的绘制动画完全停止(包括清除画布)并开始“接触”动画。目前,“接触”动画确实开始了,但“关于”动画也坚持完成。当我点击“大约”两次时,同样的事情会发生 - 动画同时运行两次......

【问题讨论】:

    标签: javascript animation canvas requestanimationframe cancelanimationframe


    【解决方案1】:

    万一它对任何人有帮助,我设法解决了它(逻辑中有一些错误,并且 cancelAnimationFrame 最终做了我需要的事情,而不是使用标志):

    HTML

    <div class="container">
        <nav>
            <ul>
                <li>
                    <a href="#about" id="about" onclick="checkDraw(this.id);">About</a>
                </li>
                <li>
                    <a href="#contact" id="contact" onclick="checkDraw(this.id);">Work</a>
                </li>
            </ul>
        </nav>
    </div>
    <canvas id="canvas"  width="500" height="500"></canvas>
    

    JavaScript

    var canvas = document.getElementById('canvas');
    var ctx = canvas.getContext('2d');
    var requestId;
    function checkDraw(contentId) {
        stopAnimation();
        draw(contentId);
    }
    
    function stopAnimation(e) {
        cancelAnimationFrame(requestId);
    }
    
    function draw(contentId) {
        currentID = contentId;
        var t = 1;
        var vertices = [];
        function calcWaypoints(vertices) {
            var waypoints = [];
            for (var i = 1; i < vertices.length; i++) {
                var pt0 = vertices[i - 1];
                var pt1 = vertices[i];
                var dx = pt1.x - pt0.x;
                var dy = pt1.y - pt0.y;
                for (var j = 0; j < 100; j++) {
                    var x = pt0.x + dx * j / 100;
                    var y = pt0.y + dy * j / 100;
                    waypoints.push({
                        x: x,
                        y: y
                    });
                }
            }
            return (waypoints);
        }
    
        function animate() {
            if (t < points.length - 1) {
                requestId = requestAnimationFrame(animate);
            }
    
            ctx.beginPath();
            ctx.moveTo(points[t - 1].x, points[t - 1].y);
            ctx.lineTo(points[t].x, points[t].y);
            ctx.stroke();
            t++;
        }
    
    // Clear the canvas before drawing
        ctx.clearRect(0, 0, canvas.width, canvas.height);
    // Assign coordinates
        if (contentId == 'about') {
            vertices.push({x: 50, y: 0}, {x: 50, y: 50});
            vertices.push({x: 40, y: 60}, {x: 0, y: 60});
    // Animate lines
            ctx.lineCap = "round";
            ctx.lineWidth = border;
            ctx.strokeStyle = "green";
            var points = calcWaypoints(vertices);
            animate(points);
        }
        if (contentId == 'contact') {
            vertices.push({x: 150, y: 0}, {x: 150, y: 50});
            vertices.push({x: 160, y: 60}, {x: 300, y: 60});
            vertices.push({x: 300, y: 70}, {x: 310, y: 70});
            ctx.lineCap = "round";
            ctx.lineWidth = border;
            ctx.strokeStyle = "green";
            var points = calcWaypoints(vertices);
            animate(points);
        }
    }
    

    我希望这是有道理的!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-26
      • 1970-01-01
      • 1970-01-01
      • 2013-03-06
      相关资源
      最近更新 更多