diff --git a/iwsy/iwsy.js b/iwsy/iwsy.js
index 646a8d4..b5b81bc 100644
--- a/iwsy/iwsy.js
+++ b/iwsy/iwsy.js
@@ -300,6 +300,40 @@ const IWSY = (playerElement, scriptObject) => {
}
};
+ // Animate a fade
+ const animateFade = (timestamp, vfx) => {
+ if (script.stop) {
+ return;
+ }
+ if (vfx.start === undefined) {
+ vfx.start = timestamp;
+ }
+ const elapsed = timestamp - vfx.start;
+ if (elapsed < vfx.duration) {
+ const ratio = 0.5 - Math.cos(Math.PI * elapsed / vfx.duration) / 2;
+ for (const block of vfx.stepBlocks)
+ {
+ block.element.style.opacity = vfx.upDown ? ratio : 1.0 - ratio;
+ }
+ requestAnimationFrame(timestamp => {
+ animateFade(timestamp, vfx);
+ });
+ } else {
+ for (const block of vfx.stepBlocks)
+ {
+ block.element.style.opacity = vfx.upDown ? 1 : 0;
+ block.element.style.display = vfx.upDown ? `block` :`none`;
+ }
+ if (!vfx.continueFlag) {
+ if (script.runMode === `manual`) {
+ enterManualMode(step);
+ } else {
+ vfx.step.next();
+ }
+ }
+ }
+ };
+
// Fade up or down
const doFade = (step, upDown) => {
const stepBlocks = [];
@@ -327,48 +361,20 @@ const IWSY = (playerElement, scriptObject) => {
}
}
} else {
- const animSteps = Math.round(step.duration * 25);
- const continueFlag = step.continue === `yes`;
for (const block of stepBlocks)
{
block.element.style.display = `block`;
}
- let animStep = 0;
- const interval = setInterval(() => {
- try {
- if (animStep < animSteps) {
- const ratio = 0.5 - Math.cos(Math.PI * animStep / animSteps) / 2;
- for (const block of stepBlocks)
- {
- // if (block.element) {
- block.element.style.opacity = upDown ? ratio : 1.0 - ratio;
- // }
- }
- animStep++;
- } else {
- for (const block of stepBlocks)
- {
- // if (block.element) {
- block.element.style.opacity = upDown ? 1 : 0;
- block.element.style.display = upDown ? `block` :`none`;
- // }
- }
- clearIntervalTimer(interval);
- if (!continueFlag) {
- if (script.runMode === `manual`) {
- enterManualMode(step);
- } else {
- step.next();
- }
- }
- }
- } catch(err) {
- clearIntervalTimer(interval);
- throw Error(err);
- }
- }, 40);
- addIntervalTimer(interval);
- if (continueFlag) {
+ const vfx = {};
+ vfx.step = step;
+ vfx.stepBlocks = stepBlocks;
+ vfx.upDown = upDown;
+ vfx.duration = step.duration * 1000;
+ vfx.continueFlag = step.continue === `yes`;
+ requestAnimationFrame(timestamp => {
+ animateFade(timestamp, vfx);
+ });
+ if (vfx.continueFlag) {
step.next();
}
}
@@ -436,7 +442,11 @@ const IWSY = (playerElement, scriptObject) => {
image.style.top = `${yoff}px`;
};
- const doPanzoom = (timestamp, vfx) => {
+ // Animate a pan-zoom
+ const animatePanzoom = (timestamp, vfx) => {
+ if (script.stop) {
+ return;
+ }
if (vfx.start === undefined) {
vfx.start = timestamp;
}
@@ -450,7 +460,7 @@ const IWSY = (playerElement, scriptObject) => {
image.style.left = `${vfx.xoff + (vfx.xoff2 - vfx.xoff) * ratio}px`;
image.style.top = `${vfx.yoff + (vfx.yoff2 - vfx.yoff) * ratio}px`;
requestAnimationFrame(timestamp => {
- doPanzoom(timestamp, vfx);
+ animatePanzoom(timestamp, vfx);
});
} else {
image.style.width = `${vfx.w2}px`;
@@ -485,7 +495,7 @@ const IWSY = (playerElement, scriptObject) => {
};
delete(vfx.start);
requestAnimationFrame(timestamp => {
- doPanzoom(timestamp, vfx);
+ animatePanzoom(timestamp, vfx);
});
break;
}
@@ -529,12 +539,46 @@ const IWSY = (playerElement, scriptObject) => {
image.addEventListener(`load`, () => {
initImage(spec);
requestAnimationFrame(timestamp => {
- doPanzoom(timestamp, vfx);
+ animatePanzoom(timestamp, vfx);
});
});
player.appendChild(image);
};
+ // Animate a crossfade
+ const animateCrossfade = (timestamp, vfx) => {
+ if (script.stop) {
+ return;
+ }
+ if (vfx.start === undefined) {
+ vfx.start = timestamp;
+ }
+ const elapsed = timestamp - vfx.start;
+ if (elapsed < vfx.duration) {
+ const ratio = 0.5 - Math.cos(Math.PI * elapsed / vfx.duration) / 2;
+ vfx.block.element.style.opacity = 1.0 - ratio;
+ vfx.element.style.opacity = ratio;
+ requestAnimationFrame(timestamp => {
+ animateCrossfade(timestamp, vfx);
+ });
+ } else {
+ vfx.block.textPanel.innerHTML = vfx.newText;
+ if (vfx.content.url) {
+ vfx.block.element.style.background = `url("${vfx.content.url}")`;
+ }
+ vfx.block.element.style[`background-size`] = `cover`;
+ vfx.block.element.style.opacity = 1.0 ;
+ removeElement(vfx.element);
+ if (!vfx.continueFlag) {
+ if (script.runMode === `manual`) {
+ enterManualMode(step);
+ } else {
+ vfx.step.next();
+ }
+ }
+ }
+ };
+
// Handle a crossfade
const crossfade = step => {
for (const content of script.content) {
@@ -545,10 +589,14 @@ const IWSY = (playerElement, scriptObject) => {
const newText = converter.makeHtml(content.content.split(`%0a`).join(`\n`));
for (const block of script.blocks) {
if (block.defaults.name === step.block) {
+ if (block.element === undefined) {
+ throw Error(`Block '${block.defaults.name}' has no DOM element.`);
+ }
if (script.speed === `scan`) {
block.textPanel.innerHTML = newText;
step.next();
} else {
+ const continueFlag = step.continue === `yes`;
const element = document.createElement(`div`);
player.appendChild(element);
element.style.position = `absolute`;
@@ -575,35 +623,18 @@ const IWSY = (playerElement, scriptObject) => {
text.style[`text-align`] = block.textPanel.style[`text-align`];
text.style.color = block.textPanel.style.color;
text.innerHTML = newText;
+ const vfx = {};
+ vfx.step = step;
+ vfx.block = block;
+ vfx.element = element;
+ vfx.content = content;
+ vfx.newText = newText;
+ vfx.duration = step.duration * 1000;
+ vfx.continueFlag = continueFlag;
+ requestAnimationFrame(timestamp => {
+ animateCrossfade(timestamp, vfx);
+ });
- const animSteps = Math.round(step.duration * 25);
- const continueFlag = step.continue === `yes`;
- let animStep = 0;
- const interval = setInterval(() => {
- if (animStep < animSteps) {
- const ratio = 0.5 - Math.cos(Math.PI * animStep / animSteps) / 2;
- block.element.style.opacity = 1.0 - ratio;
- element.style.opacity = ratio;
- animStep++;
- } else {
- clearIntervalTimer(interval);
- block.textPanel.innerHTML = newText;
- if (content.url) {
- block.element.style.background = `url("${content.url}")`;
- }
- block.element.style[`background-size`] = `cover`;
- block.element.style.opacity = 1.0 ;
- removeElement(element);
- if (!continueFlag) {
- if (script.runMode === `manual`) {
- enterManualMode(step);
- } else {
- step.next();
- }
- }
- }
- }, 40);
- addIntervalTimer(interval);
if (continueFlag) {
step.next();
}
@@ -721,6 +752,37 @@ const IWSY = (playerElement, scriptObject) => {
block.current.fontSize = target.defaults.fontSize;
};
+ // Animate a transition
+ const animateTransition = (timestamp, vfx) => {
+ if (script.stop) {
+ return;
+ }
+ if (vfx.start === undefined) {
+ vfx.start = timestamp;
+ }
+ const elapsed = timestamp - vfx.start;
+ if (elapsed < vfx.duration) {
+ const ratio = 0.5 - Math.cos(Math.PI * elapsed / vfx.duration) / 2;
+ try {
+ doTransitionStep(vfx.block, vfx.target, ratio);
+ requestAnimationFrame(timestamp => {
+ animateTransition(timestamp, vfx);
+ });
+ } catch (err) {
+ console.log(err);
+ }
+ } else {
+ setFinalState(vfx.block,vfx.target);
+ if (!vfx.continueFlag) {
+ if (script.runMode === `manual`) {
+ enterManualMode(step);
+ } else {
+ vfx.step.next();
+ }
+ }
+ }
+ };
+
// Handle a transition
const transition = step => {
let block = null;
@@ -744,31 +806,16 @@ const IWSY = (playerElement, scriptObject) => {
setFinalState(block,target);
step.next();
} else {
- const animSteps = Math.round(step.duration * 25);
- let animStep = 0;
const continueFlag = step.continue === `yes`;
- const interval = setInterval(() => {
- if (animStep < animSteps) {
- const ratio = 0.5 - Math.cos(Math.PI * animStep / animSteps) / 2;
- try {
- doTransitionStep(block, target, ratio);
- } catch (err) {
- clearIntervalTimer(interval);
- }
- animStep++;
- } else {
- clearIntervalTimer(interval);
- setFinalState(block,target);
- if (!continueFlag) {
- if (script.runMode === `manual`) {
- enterManualMode(step);
- } else {
- step.next();
- }
- }
- }
- }, 40);
- addIntervalTimer(interval);
+ const vfx = {};
+ vfx.step = step;
+ vfx.block = block;
+ vfx.target = target;
+ vfx.duration = step.duration * 1000;
+ vfx.continueFlag = continueFlag;
+ requestAnimationFrame(timestamp => {
+ animateTransition(timestamp, vfx);
+ });
if (continueFlag) {
step.next();
}
@@ -1084,7 +1131,7 @@ const IWSY = (playerElement, scriptObject) => {
if (script.runMode == `auto` || script.speed === `scan`) {
setTimeout(() => {
if (script.stop) {
- script.stop = false;
+ // script.stop = false;
restoreCursor();
} else {
doStep(nextStep);
diff --git a/iwsy/resources/scripts/demo.json b/iwsy/resources/scripts/demo.json
index 2a237f0..a0beda6 100644
--- a/iwsy/resources/scripts/demo.json
+++ b/iwsy/resources/scripts/demo.json
@@ -37,12 +37,6 @@
"duration": 2,
"continue": false
},
- {
- "title": "pause 2 seconds",
- "action": "pause",
- "label": "",
- "duration": 2
- },
{
"title": "set up title and subtitle",
"action": "set content",