Ive posted other questions but feel I should simplify things
I have one function that sets a context and calls a second function to draw the lines on the context.
I have this:
var arr = [];
which is populated like this:
arr = [context,pre];
while pre
looks like pre = [[{x:n,y:m}],[{x:j,y:k}]];
So, basically, I have an array, pre
, containing arrays of coordinates. That array is pushed with a context into arr
arr
is returned and pushed into a final array, lets say final_arr
, which now should look like this: final_arr = [[context1,pre1],[context2,pre2],...]
My goal is to loop through final_arr
and draw lines on different contexts, determined by the context
in the array. For example, the first iteration will access final_arr[0]
and contain context1,pre1
. These two values are sent to a function, wrap(context, pre)
that returns a promise. Inside this wrap
function, another function is called, animate(pre[i])
. this function takes each element in pre
, which corresponds to an array of coordinates, and actually draws the line using animation frames. animate()
also returns a promise.
Currently, only one of the paths is being drawn, which seems to be because only one value of final_arr
is being used, even though I am iterating through it
My attempts to iterate:
final_arr.reduce((a,c) => a.then(() => wrap(c[0],c[1])), Promise.resolve());
and
var temp = Promise.resolve();
var i = 0;
for (i = 0; i < arr.length; i++){
//window.alert(arr[i].length)
var ct = arr[i][0];
var line = arr[i][1];
temp.then(() => wrap(ct,line));
}
and here are the functions being called:
/*
* 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){
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();
});
}
function wrap(ctx, lines){
return new Promise(function(resolve) {
var counter = 0;
t = 1;
var getAnimation = function(){
if(counter < lines.length){
context = ctx;
lines.reduce((a, c) => a.then(() => animate(c)), Promise.resolve());
counter++;
} else {
resolve()
}
};
getAnimation();
});
}
The context
variable set in wrap
is a global variable for the js file
I hope the question asked this way provides clarity as to what I am having a problem with
Thank you for any help
Edit:
Attempted fiddle
Edit2:
Oddly enough this works
if(final_arr.length == 1){
wrap(final_arr[0][0], final_arr[0][1]);
} else if (final_arr.length == 2){
wrap(final_arr[0][0], final_arr[0][1]).then(wrap(final_arr[1][0], final_arr[1][1]));
} else if (final_arr.length == 3){
wrap(final_arr[0][0], final_arr[0][1]).then(wrap(final_arr[1][0], final_arr[1][1])).then(wrap(final_arr[2][0], final_arr[2][1]));
}
But when using this, the lines are drawn at the same time (which is okay, but not preferred)
edit: just spotted the missing resolve
inside the if
statement of wrap
=> the returned Promise will never be resolved...
I recommend to start with a much simpler version of wrap
before making any micro-optimizations:
function wrap(ctx, lines){
return new Promise(function(resolve) {
lines.forEach(p => animate(p, ctx));
resolve();
});
}
callbacks to requestAnimationFrame
are called after finishing all microtasks (i.e. after all Promises) - see When will requestAnimationFrame be executed?
so the value of the global variable context
will be the same for all of the callbacks, i.e. the same line drawn multiple times or a race condition or something depending on internals of the context
I would get rid of globals, using only function params and locals:
var animate = function(p, ctx) {
var t ...
... ctx.beginPath()
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments