【问题标题】:Javascript chaining the same animation function with different parametersJavascript用不同的参数链接相同的动画函数
【发布时间】:2018-07-20 06:34:12
【问题描述】:

我正在尝试将一条线沿一条路径设置为两条线,一条线然后另一条线。基本上它看起来就像画一条线,停在一个点,然后另一条线在其他地方画。到目前为止,我已经遇到了实现这一点的承诺和回调,但是作为一个 javascript 新手,这很令人困惑

当前动画函数:

/*
*   Animation function draws a line between every point
*/              
var animate = function(p){
    return new Promise(function(resolve) {
        t = 1;
        var runAnimation = function(){
            if(t<p.length-1){
                context.beginPath();
                context.moveTo(p[t-1].x,p[t-1].y);
                context.lineTo(p[t].x,p[t].y);
                context.stroke();
                t++;
                requestAnimationFrame(function(){runAnimation()});
            } else {
                resolve()
            }
        };
        runAnimation();
    });
}

当前调用动画函数:

animate(points).then(animate(secondary_points));

这些点类似于:

var points = [{x:100, y:200}];

而线条需要遵循的路径只是pointssecondary_points内部的多个坐标

我在 SO 上尝试了许多相似的解决方案,但细微的差异会导致我搞砸或不理解解决方案。我似乎遇到的最大问题是调用 SAME animate 函数,而该 animate 函数需要在不同的参数上运行。

没有这个解决方案,使用

animate(points);
animate(secondary_points);

线条是同时绘制的,但结果实际上只是沿路径随机放置的点而不是平滑的线条,我假设是因为两者同时运行。

我将如何解决这个问题,以便沿 path1 绘制一条线,然后沿 path2 绘制第二条线?

这可能是一个简单的解决方案,但我已经使用 JS 工作了 3 天,但我仍然无法适应我必须修复的旧代码的一些语法

谢谢

编辑:

动画的完整流程如下:

我有一个 php 文件,其中包含 2 个画布,每个画布都包含一张地图图像。 php 文件有几个&lt;script/&gt; 标签,其中一个通过drawPath(source,destination,true)drawPath(source,destination,false) 调用我正在编写动画的js 脚本

drawPath 函数使用布尔值来确定要获取哪个画布的上下文,然后通过查找路径并创建上面提到的points 在从 A 点到 B 点的路径上绘制,然后使用 animate() 进行绘制.地图中有几个中断需要单独的行,这引发了我最初的问题。多亏了建议,我才能解决这个问题,但现在我遇到了一个更大的问题。

如果我需要从地图A上的A点到地图B上的B点,即

drawPath(source, end_point_of_map_A, true); 然后被调用 drawPath(start_point_of_map_B, destination, false);,线只画在一张地图上,和之前类似,1.随机,2.不完整/只有点

我假设这又是由于动画造成的,因为它仅在静态绘制线条时起作用,并且每个动画在单个地图上从点 A 到 B 时起作用

感谢任何帮助!

编辑:

绘图路径()

function drawPath(source, desti, flag) {
    /*
    * Define context
    */
    //lower
    if(!flag){
        var c = document.getElementById("myCanvas");
        context = c.getContext("2d");
    //upper
    } else {
        var cUpr = document.getElementById("myCanvasUpr");
        context = cUpr.getContext("2d");
    }
    /*
    * Clear the variables
    */
    points = [];
    secondary_points = [];
    vertices = [];
    secondary_vertices = [];
    t = 1;
    done = false;




    //check for invalid locations
    if (source != "" && desti != "") {
        context.lineCap = 'round';
        context.beginPath();

        /*
        * Get the coordinates from source and destination strings
        */
        var src = dict[source];
        var dst = dict[desti];

        /*
        * Get the point number of the point on the path that the source and destination connect to
        */

        var begin = point_num[source];
        var finish = point_num[desti];

        /*
        * Draw the green and red starting/ending circles (green is start, red is end)
        */
        context.beginPath();
        context.arc(src[0], src[1], 8, 0, 2 * Math.PI);
        context.fillStyle = 'green';
        context.fill();

        context.beginPath();
        context.arc(dst[0], dst[1], 6, 0, 2 * Math.PI);
        context.fillStyle = 'red';
        context.fill();

        /*
        * Call the function that draws the entire path
        */
        draw_segments(begin, finish, src, dst, flag);
        //window.alert(JSON.stringify(vertices, null, 4))
        /*
        * Edit what the line looks like
        */
        context.lineWidth = 5;
        context.strokeStyle = "#ff0000";
        context.stroke();

    }
}

【问题讨论】:

  • 我不知道您是否偶然发现了this question/answer,但它似乎回答了您的问题。我根据您的问题将答案应用于此jsFiddle
  • 这个animate(points).then(animate(secondary_points));,可能需要是:animate(points).then(() =&gt; animate(secondary_points));。您必须将函数引用传递给.then(),以便稍后执行。您正在立即执行它。
  • @jfriend00 这个解决方案有效,谢谢!但是,现在我发现了一个新问题。我正在更新我的问题以解释它是相似的
  • @jfriend00 抱歉,需要一段时间来编辑
  • 首先,与您第一次询问的问题相比,此编辑似乎是一个新的和不同的问题。其次,如果没有查看所有相关代码并且没有更完整地描述应该发生的事情以及您观察到的事情发生,我认为没有人可以提供帮助。也许这属于另一个问题。

标签: javascript animation promise


【解决方案1】:

处理这个问题的一个好方法是将你的线条放入一个数组中,其中每个元素都是线条的一组点。然后您可以调用reduce() 依次触发每个承诺。 reduce() 如果您不熟悉 javascript,则需要一点时间来适应,但在这种情况下,它基本上需要数组 c 的每个元素,做一些事情,然后成为下一个 a。你以一个解决承诺开始整个事情,这将是最初的a。承诺链将由 reduce 返回给您,您可以添加最终的 then 以了解整个事情何时完成。

例如:

let canvas = document.getElementById('canvas')
let context = canvas.getContext('2d');
var animate = function(p){

    return new Promise(function(resolve) {
        t = 1;
        var runAnimation = function(){
            if(t<p.length-1){
                context.beginPath();
                context.moveTo(p[t-1].x,p[t-1].y);
                context.lineTo(p[t].x,p[t].y);
                context.stroke();
                t++;
                requestAnimationFrame(function(){runAnimation()});
            } else {
                resolve()
            }
        };
        runAnimation();
    });
}

// make some points:

let points = Array.from({length: 200}, (_,i) => ({x:i+1, y:i+2}))
let points2 = Array.from({length: 200}, (_,i) => ({x:300-i, y:i+2}))
let points3 = Array.from({length: 200}, (_,i) => ({x:i*2, y:100+100*Math.sin(i/10)}))

// create an array holding each set

let sets = [points, points2, points3]

// use reduce to call each in sequence returning the promise each time
sets.reduce((a, c) => a.then(() => animate(c)), Promise.resolve())
.then(() => console.log("done"))
&lt;canvas id="canvas" height="300" width="500"&gt;&lt;/canvas&gt;

【讨论】:

  • @ChrisM,您理解正确。 reduce 起初令人困惑。它需要一个列表 (sets) 并为每个项目调用一个带有两个 args 的函数(称为 a 用于累加器,c 用于当前此处)。该函数的返回值成为下一次调用的a。对于第一次调用,我们手动给它初始的a,即Promise.resolve()。第一遍调用Promise.resolve().then(() =&gt; animate(c)),其中'c' 是列表中的第一个元素。这会产生一个新的承诺,成为下一个a。它本质上是一个then().then()等的大链,
  • @ChrisM 是的。使用不包含承诺的示例可能更容易理解。 reduce 的经典用法是对一组数字求和。
  • @ChrisM 完全正确。 [1, 2, 3].reduce((a, c) =&gt; a + c, 0)
  • => 表示箭头函数对吗?所以等价于function(a,c){return a+c},第二个参数传递给reduce(...,0),表示初始a = 0?
  • @ChrisM 是的,我想你有它。
猜你喜欢
  • 2019-08-02
  • 2012-06-24
  • 1970-01-01
  • 1970-01-01
  • 2016-07-08
  • 2014-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多