Skip to content

Commit fdc0c0a

Browse files
committed
Use requestAnimationFrame() for all animations
1 parent 494800f commit fdc0c0a

File tree

2 files changed

+142
-101
lines changed

2 files changed

+142
-101
lines changed

iwsy/iwsy.js

Lines changed: 142 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,40 @@ const IWSY = (playerElement, scriptObject) => {
300300
}
301301
};
302302

303+
// Animate a fade
304+
const animateFade = (timestamp, vfx) => {
305+
if (script.stop) {
306+
return;
307+
}
308+
if (vfx.start === undefined) {
309+
vfx.start = timestamp;
310+
}
311+
const elapsed = timestamp - vfx.start;
312+
if (elapsed < vfx.duration) {
313+
const ratio = 0.5 - Math.cos(Math.PI * elapsed / vfx.duration) / 2;
314+
for (const block of vfx.stepBlocks)
315+
{
316+
block.element.style.opacity = vfx.upDown ? ratio : 1.0 - ratio;
317+
}
318+
requestAnimationFrame(timestamp => {
319+
animateFade(timestamp, vfx);
320+
});
321+
} else {
322+
for (const block of vfx.stepBlocks)
323+
{
324+
block.element.style.opacity = vfx.upDown ? 1 : 0;
325+
block.element.style.display = vfx.upDown ? `block` :`none`;
326+
}
327+
if (!vfx.continueFlag) {
328+
if (script.runMode === `manual`) {
329+
enterManualMode(step);
330+
} else {
331+
vfx.step.next();
332+
}
333+
}
334+
}
335+
};
336+
303337
// Fade up or down
304338
const doFade = (step, upDown) => {
305339
const stepBlocks = [];
@@ -327,48 +361,20 @@ const IWSY = (playerElement, scriptObject) => {
327361
}
328362
}
329363
} else {
330-
const animSteps = Math.round(step.duration * 25);
331-
const continueFlag = step.continue === `yes`;
332364
for (const block of stepBlocks)
333365
{
334366
block.element.style.display = `block`;
335367
}
336-
let animStep = 0;
337-
const interval = setInterval(() => {
338-
try {
339-
if (animStep < animSteps) {
340-
const ratio = 0.5 - Math.cos(Math.PI * animStep / animSteps) / 2;
341-
for (const block of stepBlocks)
342-
{
343-
// if (block.element) {
344-
block.element.style.opacity = upDown ? ratio : 1.0 - ratio;
345-
// }
346-
}
347-
animStep++;
348-
} else {
349-
for (const block of stepBlocks)
350-
{
351-
// if (block.element) {
352-
block.element.style.opacity = upDown ? 1 : 0;
353-
block.element.style.display = upDown ? `block` :`none`;
354-
// }
355-
}
356-
clearIntervalTimer(interval);
357-
if (!continueFlag) {
358-
if (script.runMode === `manual`) {
359-
enterManualMode(step);
360-
} else {
361-
step.next();
362-
}
363-
}
364-
}
365-
} catch(err) {
366-
clearIntervalTimer(interval);
367-
throw Error(err);
368-
}
369-
}, 40);
370-
addIntervalTimer(interval);
371-
if (continueFlag) {
368+
const vfx = {};
369+
vfx.step = step;
370+
vfx.stepBlocks = stepBlocks;
371+
vfx.upDown = upDown;
372+
vfx.duration = step.duration * 1000;
373+
vfx.continueFlag = step.continue === `yes`;
374+
requestAnimationFrame(timestamp => {
375+
animateFade(timestamp, vfx);
376+
});
377+
if (vfx.continueFlag) {
372378
step.next();
373379
}
374380
}
@@ -436,7 +442,11 @@ const IWSY = (playerElement, scriptObject) => {
436442
image.style.top = `${yoff}px`;
437443
};
438444

439-
const doPanzoom = (timestamp, vfx) => {
445+
// Animate a pan-zoom
446+
const animatePanzoom = (timestamp, vfx) => {
447+
if (script.stop) {
448+
return;
449+
}
440450
if (vfx.start === undefined) {
441451
vfx.start = timestamp;
442452
}
@@ -450,7 +460,7 @@ const IWSY = (playerElement, scriptObject) => {
450460
image.style.left = `${vfx.xoff + (vfx.xoff2 - vfx.xoff) * ratio}px`;
451461
image.style.top = `${vfx.yoff + (vfx.yoff2 - vfx.yoff) * ratio}px`;
452462
requestAnimationFrame(timestamp => {
453-
doPanzoom(timestamp, vfx);
463+
animatePanzoom(timestamp, vfx);
454464
});
455465
} else {
456466
image.style.width = `${vfx.w2}px`;
@@ -485,7 +495,7 @@ const IWSY = (playerElement, scriptObject) => {
485495
};
486496
delete(vfx.start);
487497
requestAnimationFrame(timestamp => {
488-
doPanzoom(timestamp, vfx);
498+
animatePanzoom(timestamp, vfx);
489499
});
490500
break;
491501
}
@@ -529,12 +539,46 @@ const IWSY = (playerElement, scriptObject) => {
529539
image.addEventListener(`load`, () => {
530540
initImage(spec);
531541
requestAnimationFrame(timestamp => {
532-
doPanzoom(timestamp, vfx);
542+
animatePanzoom(timestamp, vfx);
533543
});
534544
});
535545
player.appendChild(image);
536546
};
537547

548+
// Animate a crossfade
549+
const animateCrossfade = (timestamp, vfx) => {
550+
if (script.stop) {
551+
return;
552+
}
553+
if (vfx.start === undefined) {
554+
vfx.start = timestamp;
555+
}
556+
const elapsed = timestamp - vfx.start;
557+
if (elapsed < vfx.duration) {
558+
const ratio = 0.5 - Math.cos(Math.PI * elapsed / vfx.duration) / 2;
559+
vfx.block.element.style.opacity = 1.0 - ratio;
560+
vfx.element.style.opacity = ratio;
561+
requestAnimationFrame(timestamp => {
562+
animateCrossfade(timestamp, vfx);
563+
});
564+
} else {
565+
vfx.block.textPanel.innerHTML = vfx.newText;
566+
if (vfx.content.url) {
567+
vfx.block.element.style.background = `url("${vfx.content.url}")`;
568+
}
569+
vfx.block.element.style[`background-size`] = `cover`;
570+
vfx.block.element.style.opacity = 1.0 ;
571+
removeElement(vfx.element);
572+
if (!vfx.continueFlag) {
573+
if (script.runMode === `manual`) {
574+
enterManualMode(step);
575+
} else {
576+
vfx.step.next();
577+
}
578+
}
579+
}
580+
};
581+
538582
// Handle a crossfade
539583
const crossfade = step => {
540584
for (const content of script.content) {
@@ -545,10 +589,14 @@ const IWSY = (playerElement, scriptObject) => {
545589
const newText = converter.makeHtml(content.content.split(`%0a`).join(`\n`));
546590
for (const block of script.blocks) {
547591
if (block.defaults.name === step.block) {
592+
if (block.element === undefined) {
593+
throw Error(`Block '${block.defaults.name}' has no DOM element.`);
594+
}
548595
if (script.speed === `scan`) {
549596
block.textPanel.innerHTML = newText;
550597
step.next();
551598
} else {
599+
const continueFlag = step.continue === `yes`;
552600
const element = document.createElement(`div`);
553601
player.appendChild(element);
554602
element.style.position = `absolute`;
@@ -575,35 +623,18 @@ const IWSY = (playerElement, scriptObject) => {
575623
text.style[`text-align`] = block.textPanel.style[`text-align`];
576624
text.style.color = block.textPanel.style.color;
577625
text.innerHTML = newText;
626+
const vfx = {};
627+
vfx.step = step;
628+
vfx.block = block;
629+
vfx.element = element;
630+
vfx.content = content;
631+
vfx.newText = newText;
632+
vfx.duration = step.duration * 1000;
633+
vfx.continueFlag = continueFlag;
634+
requestAnimationFrame(timestamp => {
635+
animateCrossfade(timestamp, vfx);
636+
});
578637

579-
const animSteps = Math.round(step.duration * 25);
580-
const continueFlag = step.continue === `yes`;
581-
let animStep = 0;
582-
const interval = setInterval(() => {
583-
if (animStep < animSteps) {
584-
const ratio = 0.5 - Math.cos(Math.PI * animStep / animSteps) / 2;
585-
block.element.style.opacity = 1.0 - ratio;
586-
element.style.opacity = ratio;
587-
animStep++;
588-
} else {
589-
clearIntervalTimer(interval);
590-
block.textPanel.innerHTML = newText;
591-
if (content.url) {
592-
block.element.style.background = `url("${content.url}")`;
593-
}
594-
block.element.style[`background-size`] = `cover`;
595-
block.element.style.opacity = 1.0 ;
596-
removeElement(element);
597-
if (!continueFlag) {
598-
if (script.runMode === `manual`) {
599-
enterManualMode(step);
600-
} else {
601-
step.next();
602-
}
603-
}
604-
}
605-
}, 40);
606-
addIntervalTimer(interval);
607638
if (continueFlag) {
608639
step.next();
609640
}
@@ -721,6 +752,37 @@ const IWSY = (playerElement, scriptObject) => {
721752
block.current.fontSize = target.defaults.fontSize;
722753
};
723754

755+
// Animate a transition
756+
const animateTransition = (timestamp, vfx) => {
757+
if (script.stop) {
758+
return;
759+
}
760+
if (vfx.start === undefined) {
761+
vfx.start = timestamp;
762+
}
763+
const elapsed = timestamp - vfx.start;
764+
if (elapsed < vfx.duration) {
765+
const ratio = 0.5 - Math.cos(Math.PI * elapsed / vfx.duration) / 2;
766+
try {
767+
doTransitionStep(vfx.block, vfx.target, ratio);
768+
requestAnimationFrame(timestamp => {
769+
animateTransition(timestamp, vfx);
770+
});
771+
} catch (err) {
772+
console.log(err);
773+
}
774+
} else {
775+
setFinalState(vfx.block,vfx.target);
776+
if (!vfx.continueFlag) {
777+
if (script.runMode === `manual`) {
778+
enterManualMode(step);
779+
} else {
780+
vfx.step.next();
781+
}
782+
}
783+
}
784+
};
785+
724786
// Handle a transition
725787
const transition = step => {
726788
let block = null;
@@ -744,31 +806,16 @@ const IWSY = (playerElement, scriptObject) => {
744806
setFinalState(block,target);
745807
step.next();
746808
} else {
747-
const animSteps = Math.round(step.duration * 25);
748-
let animStep = 0;
749809
const continueFlag = step.continue === `yes`;
750-
const interval = setInterval(() => {
751-
if (animStep < animSteps) {
752-
const ratio = 0.5 - Math.cos(Math.PI * animStep / animSteps) / 2;
753-
try {
754-
doTransitionStep(block, target, ratio);
755-
} catch (err) {
756-
clearIntervalTimer(interval);
757-
}
758-
animStep++;
759-
} else {
760-
clearIntervalTimer(interval);
761-
setFinalState(block,target);
762-
if (!continueFlag) {
763-
if (script.runMode === `manual`) {
764-
enterManualMode(step);
765-
} else {
766-
step.next();
767-
}
768-
}
769-
}
770-
}, 40);
771-
addIntervalTimer(interval);
810+
const vfx = {};
811+
vfx.step = step;
812+
vfx.block = block;
813+
vfx.target = target;
814+
vfx.duration = step.duration * 1000;
815+
vfx.continueFlag = continueFlag;
816+
requestAnimationFrame(timestamp => {
817+
animateTransition(timestamp, vfx);
818+
});
772819
if (continueFlag) {
773820
step.next();
774821
}
@@ -1084,7 +1131,7 @@ const IWSY = (playerElement, scriptObject) => {
10841131
if (script.runMode == `auto` || script.speed === `scan`) {
10851132
setTimeout(() => {
10861133
if (script.stop) {
1087-
script.stop = false;
1134+
// script.stop = false;
10881135
restoreCursor();
10891136
} else {
10901137
doStep(nextStep);

iwsy/resources/scripts/demo.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,6 @@
3737
"duration": 2,
3838
"continue": false
3939
},
40-
{
41-
"title": "pause 2 seconds",
42-
"action": "pause",
43-
"label": "",
44-
"duration": 2
45-
},
4640
{
4741
"title": "set up title and subtitle",
4842
"action": "set content",

0 commit comments

Comments
 (0)