I want to create a messenger component that, when the function is called, will create a message and, when pressed or by a timer, will at first make it transparent -> after that, smoothly decrease the height of the wrapper ->, and after the end of the transition, delete the object
How can can I do that
My code is not working correctly
<template>
<div class="message" id="wrapper"></div>
</template>
<style lang="scss">
$height-block: 9vmin;
.message {
position: absolute;
z-index: 10;
right: 1vmin;
bottom: 1vmin;
width: 25vmin;
height: 50vmin;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: flex-end;
.wrapper {
* {
box-sizing: border-box;
}
flex-shrink: 0;
width: 100%;
position: relative;
transition: height 0.5s linear;
transition: margin 0.5s linear;
height: $height-block;
padding: 0.5vmin 0;
&__block {
background: rgba(42, 29, 29, 0.8);
height: 100%;
width: 100%;
font-size: 2vmin;
padding: 1vmin;
color: white;
display: flex;
align-items: center;
justify-content: center;
transition: opacity 0.5s linear;
}
}
}
</style>
<script>
export default {
name: "Messenger",
};
//eslint-disable-next-line no-unused-vars
window.msg = function msg(msg) {
let wrapper = document.createElement("div");
wrapper.classList.add("wrapper");
document.getElementById("wrapper").appendChild(wrapper);
let wrapper__block = document.createElement("div");
wrapper__block.classList.add("wrapper__block");
wrapper.appendChild(wrapper__block);
wrapper__block.innerHTML = msg;
setTimeout(() => {
wrapper__block.style.opacity = "0";
}, 1000);
wrapper__block.addEventListener("mousedown", () => {
wrapper__block.style.opacity = "0";
});
wrapper__block.addEventListener("transitionend", () => {
wrapper.parentElement.style.height = "0";
wrapper.parentElement.style.margin = "0";
});
wrapper.addEventListener("transitionend", () => {
wrapper.remove(wrapper__block);
});
};
</script>
Related
Just like the above image or an idea or reference to achieve this design, I appreciate the help or suggestion given by community thank you
I have got reference of progress bar which is circular but not able find an approach to solve it.
const boxes = document.querySelectorAll(".box");
const colors = ['red', 'blue', 'green', 'yellow', 'orange', 'violet']
boxes.forEach((box) => {
const insideContent = box.innerText;
box.style.border = `6px solid ${colors[insideContent]}`
})
#app {
display: flex;
}
.box {
width: 50px;
height: 50px;
margin: 10px;
background-color: cyan;
display: flex;
justify-content: center;
align-items: center;
}
<div id="app">
<div class="box">1</div>
<div class="box">2</div>
<div class="box">3</div>
</div>
As per your question I think this is what you are trying to achieve.
First define a pseudo class root
:root {
--color-val: blue;
}
Note: In order to use the --color-val you need to write it as color: var(--color-var) in CSS
Second use JavaScript to update the variable --color-val
let colors =
var root = document.querySelector(':root');
const delay = ms => new Promise(res => setTimeout(res, ms));
const colorChange = async () => {
await delay(1000);
color = colors[Math.floor(Math.random() * colors.length)]
console.log(color)
root.style.setProperty('--color-val', color);
};
colorChange()
Note:
Add the color list you want to select from or go to CodePen for a list of 1000+ hex codes.
Promise are used for asynchronous function and can be skipped by using setTimeOut for a delayed loop or if used with another eventlistener.
I apologize if I misunderstood the question. Wrote in a hurry and without beautyful visualisation, if you disassemble the principle, you can customize it.
h1 {
display: block;
margin:0 auto;
text-align: center;
padding-top:20%;
}
.container {
display:flex;
width: 150px;
height: 150px;
border: 1px solid black;
z-index: 110;
margin:0;
margin: -10px;
}
.top {
display:block;
background-color: green;
height: 24px;
width: 150px; /* gorizontal top */
animation: top 1s linear;
animation-fill-mode: forwards;
}
#keyframes top {
0% {
width: 0px;
}
100% {
width: 150px;
}
}
.right {
background-color: green;
height: 0%;/* right */
width: 32px;
animation: right 1s linear;
animation-fill-mode: forwards;
animation-delay: 1s;
z-index: 10;
}
#keyframes right {
0% {
height: 0%;
}
100% {
height: 100%;
}
}
.box {
position: fixed;
top: 32.5px;
left: 32.5px;
width: 100px;
height: 100px;
border: 1px solid black;
margin: auto;
z-index: 120;
margin: -10px -10px;
}
.bottom {
position: absolute;
top: 123px;
left: 150px;
background-color: green;
width: 0px;
height: 27px;
z-index: 10;
animation: bottom 1s linear;
animation-fill-mode: forwards;
animation-delay: 2s;
/* animation-direction: reverse; */
}
#keyframes bottom {
0% {
transform: translate(0,0);
}
100% {
transform: translate(-250px,0);
-webkit-transform: translate(-250px,0); /** Safari & Chrome **/
-o-transform: translate(-250px,0); /** Opera **/
-moz-transform: translate(-250px,0); /** Firefox **/
width: 250px;
}
}
.left {
position: absolute;
top: 122px;
background-color: green;
width: 25px;
height: 0px;
animation: left 1s linear;
animation-fill-mode: forwards;
animation-delay: 3s;
}
#keyframes left {
0% {
transform: translate(0,0);
}
100% {
transform: translate(0,-250px);
-webkit-transform: translate(0,-250px); /** Safari & Chrome **/
-o-transform: translate(0,-250px); /** Opera **/
-moz-transform: translate(0,-250px); /** Firefox **/
height: 277px;
}
}
<div class='head'>
<div class='container'>
<div class='top'></div>
<div class='box'>
<h1 id='timer'>
1
</h1>
</div>
<div class='right'></div>
<div class='bottom'></div>
<div class='left'></div>
</div>
</div>
<script type="text/javascript">
init()
function init()
{
sec = 0;
setInterval(tick, 1000);
}
function tick()
{ if (sec<3) { sec++
document.getElementById("timer").
childNodes[0].nodeValue = sec;
} else {
clearInterval(0);
}
}
</script>
Also, instead of the SetInterval script, you can take values from your block width and height styles and output a mathematical calculation in h1 instead of a stopwatch.
upd: After your comment, I decided to do what I wrote about above. You can play with values and math, I add a snippet of another solution that changes the progress bar from the entered values within the entered range. (of course, it would be easier on react than on pure js)
function grade () {
let grade = +document.getElementById("grade").value;
let range = +document.getElementById("range").value;
document.getElementById("timer").innerHTML = `${grade}/${range}`;
progress(grade,range)
}
function progress (value, grade) {
document.getElementById('1').style.backgroundColor = `white`
document.getElementById("left").className = "noactive";
document.getElementById('top').style.width = `0%`
document.getElementById('right').style.height = `0%`
document.getElementById('bottom').style.width = `0%`
let GradeValuSide = grade/4;
if (value <= GradeValuSide) {
document.getElementById('top').style.width =
`${value/GradeValuSide*100}%`
} else if (value > GradeValuSide && value <= (GradeValuSide*2)) {
document.getElementById('top').style.width = `100%`
document.getElementById('right').style.height =
`${(value-GradeValuSide)/GradeValuSide*100}%`
} else if (value >= grade/2 && value < (grade/4)*3) {
document.getElementById('top').style.width = `100%`
document.getElementById('right').style.height = `100%`
document.getElementById('bottom').style.width =
`${((((value-(GradeValuSide*2)) / GradeValuSide) *100) / 100) *27}%`
} else if (value >= grade-(grade/4) /* && value < value + 1 */) {
document.getElementById('top').style.width = `100%`
document.getElementById('right').style.height = `100%`
document.getElementById('bottom').style.width = `100%`
document.getElementById('1').style.backgroundColor = `green`
document.getElementById("left").className = "left";
document.getElementById('left').style.height =
`${(40 - (40 * ((((value-(GradeValuSide*3)) * 100) / GradeValuSide)/ 100)))}%`
}
}
h1 {
font-size:20px;
position: absolute;
left: 40px;
display: block;
margin: 0 auto;
align-items: center;
padding-top:10%;
}
.container {
display:flex;
width: 150px;
height: 150px;
border: 1px solid black;
margin:0;
margin: -10px;
}
div.top {
display:block;
background-color: green;
height: 24px;
width: 0%; /* gorizontal top */
z-index:999;
}
div.right {
position:relative;
background-color: green;
height: 0%;/* right */
width: 32px;
z-index: 9999;
}
.box {
position: fixed;
top: 32.5px;
left: 32.5px;
background-color:white;
width: 100px;
height: 100px;
border: 1px solid black;
margin: auto;
z-index: 120;
margin: -10px -10px;
}
.wrap{
position: relative;
}
div.bottom {
position: absolute;
top: 123px;
background-color: green;
width: 0%; /* 27 = 100% */
height: 27px;
float: right;
right: 78vw;
z-index: 100;
}
div.left {
position: absolute;
background-color: white;
width: 23px;
height: 40%;
top: 23px;
bottom: 10px;
left: 0;
float: top;
}
div.noactive {
position: absolute;
background-color: white;
width: 23px;
height: 0%;
top: 23px;
bottom: 10px;
left: 0;
float: top;
}
.items {
margin-top: 50px;
text-align: center;
}
.grade,
.value {
height: 15px;
width: 50px;
align-items: center;
}
<div class='head'>
<div id='1' class='container'>
<div id='top' class='top'></div>
<div class='box'>
<h1 id='timer'>1</h1>
<div class='items'>
value<input id='grade' class='grade' type=number oninput="grade()"/>
range<input id='range' class='value' type=number oninput="grade()"/>
</div>
</div>
<div id='right' class='right'></div>
<div id='bottom' class='bottom'></div>
<div id='left' class='noactive'></div>
</div>
</div>
<script src='app.js'></script>
I'm a front-end beginner and I want to make an effect now!
When you click the button on the red card, let the red move down and fade out, while the blue card slides down from above.
When you click the blue button again, it turns blue and moves down to fade out, and the red card slides down from above.
But I only make the red card move down, and it has no effect when I want to click the button of the blue card.
I'm sorry that my whole logic is stuck, I hope I can ask for your help here, thank you in advance.
The effect I want to do is similar to this URL below
enter link description here
I made a screenshot as an example
let btn = document.querySelector('.btn');
let btn2 = document.querySelector('.btn2');
btn.addEventListener('click', function() {
$('.card1').addClass('active');
})
btn2.addEventListener('click', function() {
$('.card2').addClass('active');
})
body {
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.wrap {
position: relative;
}
.wrap .card1 {
width: 500px;
height: 300px;
background-color: red;
border-radius: 20px;
display: flex;
justify-content: center;
align-items: flex-end;
}
.wrap .card1 .btn {
width: 100px;
height: 50px;
border-radius: 50px;
margin-bottom: 10px;
}
.wrap .card2 {
position: absolute;
top: 0px;
width: 500px;
height: 300px;
background-color: blue;
border-radius: 20px;
z-index: -1;
display: flex;
justify-content: center;
align-items: flex-end;
}
.wrap .card2 .btn2 {
width: 100px;
height: 50px;
border-radius: 50px;
margin-bottom: 10px;
}
.active {
-webkit-animation-iteration-count: 1;
animation-iteration-count: 1;
-webkit-animation-name: moveup;
animation-name: moveup;
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
#-webkit-keyframes moveup {
from {
opacity: 1;
}
to {
transform: translatey(20px);
display: none;
opacity: 0;
}
}
#keyframes moveup {
from {
opacity: 1;
}
to {
transform: translatey(20px);
display: none;
opacity: 0;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrap">
<div class="card1">
<input type="button" value="save" class="btn">
</div>
<div class="card2">
<input type="button" value="recalculate" class="btn2">
</div>
</div>
I made this code for you, hope you find it helpful, if you have any doubt I will be glad to help you out.
function card2Show() {
var card2 = document.getElementById('card2');
var card1 = document.getElementById('card1');
//card1 down transition
card1.style.transform = "translateY(131px)"; //this move the card down
card1.style.filter = "opacity(0)"; //this changes the opacity of the card to desapeare it
//this timeout is set to give time to the first animation to finish
setTimeout(() => {
card1.style.display = "none";
//here is the card2 animation to apear
card2.style.transform = "translateY(-131px)";
card2.style.filter = "opacity(0)";
card2.style.display = "block";
setTimeout(() => {
card2.style.filter = "opacity(1)";
card2.style.transform = "translateY(0)";
}, 60)
}, 450)
}
function card1Show() {
var card2 = document.getElementById('card2');
var card1 = document.getElementById('card1');
//card1 down transition
card2.style.transform = "translateY(-131px)"; //this move the card down
card2.style.filter = "opacity(0)"; //this changes the opacity of the card to desapeare it
//this timeout is set to give time to the first animation to finish
setTimeout(() => {
card2.style.display = "none";
//here is the card2 animation to apear
card1.style.transform = "translateY(131px)";
card1.style.filter = "opacity(0)";
card1.style.display = "block";
setTimeout(() => {
card1.style.filter = "opacity(1)";
card1.style.transform = "translateY(0)";
}, 60)
}, 450)
}
.cardsContainer {
background-color: red;
max-height: 180px;
min-height: 180px;
overflow: hidden;
padding: 20px;
display: flex;
justify-content: center;
align-items: center;
}
.card1 {
height: 100px;
transition: all .6s ease,filter .5s ease;
padding: 20px;
background-color:white;
}
.card2 {
display: none;
height: 100px;
padding: 20px;
background-color:white;
transition: all .6s ease;
}
<section>
<div class="col-12 cardsContainer">
<div class="col-8">
<div id="card1" class="card card1">
<div class="card-body">
<button onclick="card2Show()">Show card2</button>
</div>
</div>
<div id="card2" class="card card2">
<div class="card-body">
<button onclick="card1Show()">Show card1</button>
</div>
</div>
</div>
</div>
</section>
I'm trying to follow this IVS sample, the only difference is using the JW player, I following this documentation
The problem is that this snippet
jwplayer(videoPlayer).addEventListener(
PlayerEventType.TEXT_METADATA_CUE,
function (cue) {
const metadataText = cue.text;
const position = player.getPosition().toFixed(2);
console.log(
`Player Event - TEXT_METADATA_CUE: "${metadataText}". Observed ${position}s after playback started.`
);
triggerQuiz(metadataText);
}
);
is giving this error
script.js:60 Uncaught TypeError: Cannot read properties of undefined (reading 'TEXT_METADATA_CUE')
I'm either not adding an event listener to the jw player correctly or I'm doing something wrong while working with IVS.
My full code is below
const playbackUrl =
"https://fcc3ddae59ed.us-west-2.playback.live-video.net/api/video/v1/us-west-2.893648527354.channel.xhP3ExfcX8ON.m3u8";
const videoPlayer = document.getElementById("video-player");
const quizEl = document.getElementById("quiz");
const waitMessage = document.getElementById("waiting");
const questionEl = document.getElementById("question");
const answersEl = document.getElementById("answers");
const cardInnerEl = document.getElementById("card-inner");
var ivsPlayer = {};
var ivsEvents = {};
const ivsConfig = {
playlist: [
{
file: playbackUrl,
type: "ivs",
},
],
};
(function (ivsPlayer) {
jwplayer(videoPlayer)
.setup(ivsConfig)
.on("providerPlayer", function (player) {
console.log("Amazon IVS Player: ", player.ivsPlayer);
console.log("Amazon IVS Player Events: ", player.ivsEvents);
// store the reference to the Amazon IVS Player
ivsPlayer = player.ivsPlayer;
// store the reference to the Amazon IVS Player Events
ivsEvents = player.ivsEvents;
});
const PlayerState = ivsPlayer.PlayerState;
const PlayerEventType = ivsPlayer.PlayerEventType;
jwplayer(videoPlayer).addEventListener(
PlayerEventType.TEXT_METADATA_CUE,
function (cue) {
const metadataText = cue.text;
const position = player.getPosition().toFixed(2);
console.log(
`Player Event - TEXT_METADATA_CUE: "${metadataText}". Observed ${position}s after playback started.`
);
triggerQuiz(metadataText);
}
);
// Setup stream and play
// Remove card
function removeCard() {
quizEl.classList.toggle("drop");
}
// Trigger quiz
function triggerQuiz(metadataText) {
let obj = JSON.parse(metadataText);
quizEl.style.display = "";
quizEl.classList.remove("drop");
waitMessage.style.display = "none";
cardInnerEl.style.display = "none";
cardInnerEl.style.pointerEvents = "auto";
while (answersEl.firstChild) answersEl.removeChild(answersEl.firstChild);
questionEl.textContent = obj.question;
let createAnswers = function (obj, i) {
let q = document.createElement("a");
let qText = document.createTextNode(obj.answers[i]);
answersEl.appendChild(q);
q.classList.add("answer");
q.appendChild(qText);
q.addEventListener("click", (event) => {
cardInnerEl.style.pointerEvents = "none";
if (q.textContent === obj.answers[obj.correctIndex]) {
q.classList.toggle("correct");
} else {
q.classList.toggle("wrong");
}
setTimeout(function () {
removeCard();
waitMessage.style.display = "";
}, 1050);
return false;
});
};
for (var i = 0; i < obj.answers.length; i++) {
createAnswers(obj, i);
}
cardInnerEl.style.display = "";
}
waitMessage.style.display = "";
})(window.ivsPlayer);
Edit see the snippet
const playbackUrl =
"https://fcc3ddae59ed.us-west-2.playback.live-video.net/api/video/v1/us-west-2.893648527354.channel.xhP3ExfcX8ON.m3u8";
const ivsConfig = {
playlist: [
{
file: playbackUrl,
type: "ivs",
},
],
};
const videoPlayer = document.getElementById("video-player");
const quizEl = document.getElementById("quiz");
const waitMessage = document.getElementById("waiting");
const questionEl = document.getElementById("question");
const answersEl = document.getElementById("answers");
const cardInnerEl = document.getElementById("card-inner");
(async (IVSPlayer) => {
try {
const playerInstance = jwplayer(videoPlayer).setup(ivsConfig);
playerInstance.on("providerPlayer", function (player) {
console.log("Amazon IVS Player: ", player.ivsPlayer);
console.log("Amazon IVS Player Events: ", player.ivsEvents);
const PlayerEventType = player.ivsEvents;
playerInstance.addEventListener(
PlayerEventType.TEXT_METADATA_CUE,
function (cue) {
const metadataText = cue.text;
const position = player.getPosition().toFixed(2);
console.log(metadataText);
//console.log(
// `Player Event - TEXT_METADATA_CUE: "${metadataText}". Observed ${position}s after playback started.`
//);
//onsole.log(cue);
//triggerQuiz(metadataText);
}
);
});
} catch (e) {
console.error(e);
}
function triggerQuiz(metadataText) {
let obj = JSON.parse(metadataText);
quizEl.style.display = "";
quizEl.classList.remove("drop");
waitMessage.style.display = "none";
cardInnerEl.style.display = "none";
cardInnerEl.style.pointerEvents = "auto";
while (answersEl.firstChild) answersEl.removeChild(answersEl.firstChild);
questionEl.textContent = obj.question;
let createAnswers = function (obj, i) {
let q = document.createElement("a");
let qText = document.createTextNode(obj.answers[i]);
answersEl.appendChild(q);
q.classList.add("answer");
q.appendChild(qText);
q.addEventListener("click", (event) => {
cardInnerEl.style.pointerEvents = "none";
if (q.textContent === obj.answers[obj.correctIndex]) {
q.classList.toggle("correct");
} else {
q.classList.toggle("wrong");
}
setTimeout(function () {
removeCard();
waitMessage.style.display = "";
}, 1050);
return false;
});
};
for (var i = 0; i < obj.answers.length; i++) {
createAnswers(obj, i);
}
cardInnerEl.style.display = "";
}
waitMessage.style.display = "";
})(window.IVSPlayer);
/* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. */
/* SPDX-License-Identifier: MIT-0 */
/* Reset */
*,*::before,*::after{box-sizing:border-box}ul[class],ol[class]{padding:0}body,h1,h2,h3,h4,p,ul[class],ol[class],figure,blockquote,dl,dd{margin:0}html{scroll-behavior:smooth}body{min-height:100vh;text-rendering:optimizeSpeed;line-height:1.5}ul[class],ol[class]{list-style:none}a:not([class]){text-decoration-skip-ink:auto}img{max-width:100%;display:block}article>*+*{margin-top:1em}input,button,textarea,select{font:inherit}#media (prefers-reduced-motion:reduce){*{animation-duration:0.01ms!important;animation-iteration-count:1!important;transition-duration:0.01ms!important;scroll-behavior:auto!important}}
/* Variables */
:root {
--radius: 12px;
}
/* Style */
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
body {
overflow: hidden;
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", sans-serif;
user-select: none;
}
#app {
background: #334273;
height: 100%;
}
.inner {
max-width: 1080px;
display: flex;
flex-direction: column;
position: relative;
align-items: stretch;
margin: 0 auto;
padding: 40px;
}
.player-wrapper {
width: 100%;
position: relative;
overflow: hidden;
transform: translate3d(0, 0, 0);
backface-visibility: hidden;
border-radius: var(--radius);
box-shadow: 0 6px 30px rgba(0, 0, 0, 0.3);
z-index: 1;
}
.aspect-spacer {
padding-bottom: 56.25%;
}
.el-player {
width: 100%;
height: 100%;
position: absolute;
top: 0;
background: #000;
border-radius: var(--radius);
}
video {
width: 100%;
border-radius: var(--radius);
background: #000;
}
.quiz-wrap {
min-height: 460px;
position: relative;
transition: all 0.25s ease-in;
}
.card {
margin: 0 20px;
padding: 20px;
position: absolute;
left: 0;
right: 0;
background: #fff;
border-radius: 20px;
box-shadow: 0px 10px 20px rgba(0, 0, 0, 0.1);
transition: all 1s cubic-bezier(1, -0.56, 0, 1);
transform: translate3d(0, 0, 0) scale(1);
backface-visibility: hidden;
z-index: 1;
}
.card.drop {
opacity: 0;
transform: translate3d(0, 200px, -20px) scale(0.92);
}
h2 {
font-size: 25px;
text-align: center;
padding-bottom: 20px;
}
.answer {
height: 50px;
line-height: 50px;
font-size: 20px;
display: flex;
text-decoration: none;
border: 1px solid #d5dbdb;
border-radius: 50px;
padding: 0 24px;
margin: 10px 0;
background: #fafafa;
color: #545b64;
transition: all 0.05s ease-in-out;
}
.answer:hover {
background: #ebebebe0;
}
.answer:active {
background: #ff9900;
border: 1px solid #eb5f07;
color: #fff;
}
.answer.correct {
background: #25a702;
border: 1px solid #1d8102;
color: #fff;
animation: blink 0.45s infinite;
}
.answer.wrong {
background: #d13212;
border: 1px solid #b7290d;
color: #fff;
animation: blink 0.45s infinite;
}
#waiting {
top: 100px;
left: 0;
right: 0;
position: absolute;
display: flex;
align-items: center;
}
.waiting-text {
width: 100%;
display: block;
text-align: center;
font-size: 18px;
color: #d5dbdb;
}
.float {
transform: translateY(0px);
animation: float 6s ease-in-out infinite;
}
/* Utility - Position */
.pos-absolute {
position: absolute !important;
}
.pos-fixed {
position: fixed !important;
}
.pos-relative {
position: relative !important;
}
.top-0 {
top: 0 !important;
}
.bottom-0 {
bottom: 0 !important;
}
/* Utility - Width/Height */
.full-width {
width: 100%;
}
.full-height {
height: 100%;
}
/* Animations */
#keyframes blink {
50% {
opacity: 0.8;
}
}
#keyframes float {
0% {
transform: translateY(0px);
}
50% {
transform: translateY(-20px);
}
100% {
transform: translateY(0px);
}
}
/* Mediaqueries */
#media (max-width: 767px) {
h2 {
font-size: 20px;
}
.card {
top: -20px;
}
}
#media (min-width: 767px) {
.card {
top: -25%;
}
}
<head>
<script src="https://content.jwplatform.com/libraries/oH2wJDod.js"></script>
<script src="https://player.live-video.net/1.11.0/amazon-ivs-jw-provider.min.js"></script>
</head>
<body>
<div id="app">
<div class="inner">
<!-- Player wrapper, forcing 16:9 aspect ratio -->
<div class="player-wrapper">
<div class="aspect-spacer"></div>
<div class="pos-absolute full-width full-height top-0">
<div id="video-player"></div>
</div>
</div>
<!-- Quiz UI -->
<div class="quiz-wrap">
<div id="waiting">
<span class="waiting-text float"
>Waiting for the next question</span
>
</div>
<div id="quiz" class="card drop">
<div id="card-inner">
<h2 id="question"></h2>
<div id="answers"></div>
</div>
</div>
</div>
</div>
</div>
<script src="script.js"></script>
</body>
You are inside IIFE you can't declare outside of scope IIFE's are anonymous
Please read docume
const playbackUrl =
"https://fcc3ddae59ed.us-west-2.playback.live-video.net/api/video/v1/us-west-2.893648527354.channel.xhP3ExfcX8ON.m3u8";
const ivsConfig = {
playlist: [
{
file: playbackUrl,
type: "ivs"
}
]
};
const videoPlayer = document.getElementById("video-player");
const quizEl = document.getElementById("quiz");
const waitMessage = document.getElementById("waiting");
const questionEl = document.getElementById("question");
const answersEl = document.getElementById("answers");
const cardInnerEl = document.getElementById("card-inner");
(async (IVSPlayer) => {
try {
const playerInstance = jwplayer(videoPlayer).setup(ivsConfig);
playerInstance.on("providerPlayer", function (player) {
if (player) {
const { ivsEvents, ivsPlayer } = player;
ivsPlayer.addEventListener(
ivsEvents.PlayerEventType.TEXT_METADATA_CUE,
function (cue) {
const metadataText = cue.text;
// const position = player.getPosition().toFixed(2);
// position is under state.
const position = ivsPlayer.core.state.position.toFixed(2);
console.log(
`Player Event - TEXT_METADATA_CUE: "${metadataText}". Observed ${position}s after playback started.`
);
triggerQuiz(metadataText);
}
);
}
});
} catch (e) {
console.error(e);
}
function triggerQuiz(metadataText) {
let obj = JSON.parse(metadataText);
quizEl.style.display = "";
quizEl.classList.remove("drop");
waitMessage.style.display = "none";
cardInnerEl.style.display = "none";
cardInnerEl.style.pointerEvents = "auto";
while (answersEl.firstChild) answersEl.removeChild(answersEl.firstChild);
questionEl.textContent = obj.question;
let createAnswers = function (obj, i) {
let q = document.createElement("a");
let qText = document.createTextNode(obj.answers[i]);
answersEl.appendChild(q);
q.classList.add("answer");
q.appendChild(qText);
q.addEventListener("click", (event) => {
cardInnerEl.style.pointerEvents = "none";
if (q.textContent === obj.answers[obj.correctIndex]) {
q.classList.toggle("correct");
} else {
q.classList.toggle("wrong");
}
setTimeout(function () {
// removeCard(); is not defined. you must
// create it first
waitMessage.style.display = "";
}, 1050);
return false;
});
};
for (var i = 0; i < obj.answers.length; i++) {
createAnswers(obj, i);
}
cardInnerEl.style.display = "";
}
waitMessage.style.display = "";
})(window.IVSPlayer);
/* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. */
/* SPDX-License-Identifier: MIT-0 */
/* Reset */
*,
*::before,
*::after {
box-sizing: border-box;
}
ul[class],
ol[class] {
padding: 0;
}
body,
h1,
h2,
h3,
h4,
p,
ul[class],
ol[class],
figure,
blockquote,
dl,
dd {
margin: 0;
}
html {
scroll-behavior: smooth;
}
body {
min-height: 100vh;
text-rendering: optimizeSpeed;
line-height: 1.5;
}
ul[class],
ol[class] {
list-style: none;
}
a:not([class]) {
text-decoration-skip-ink: auto;
}
img {
max-width: 100%;
display: block;
}
article > * + * {
margin-top: 1em;
}
input,
button,
textarea,
select {
font: inherit;
}
#media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
/* Variables */
:root {
--radius: 12px;
}
/* Style */
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
body {
overflow: hidden;
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Ubuntu, "Helvetica Neue", sans-serif;
user-select: none;
}
#app {
background: #334273;
height: 100%;
}
.inner {
max-width: 1080px;
display: flex;
flex-direction: column;
position: relative;
align-items: stretch;
margin: 0 auto;
padding: 40px;
}
.player-wrapper {
width: 100%;
position: relative;
overflow: hidden;
transform: translate3d(0, 0, 0);
backface-visibility: hidden;
border-radius: var(--radius);
box-shadow: 0 6px 30px rgba(0, 0, 0, 0.3);
z-index: 1;
}
.aspect-spacer {
padding-bottom: 56.25%;
}
.el-player {
width: 100%;
height: 100%;
position: absolute;
top: 0;
background: #000;
border-radius: var(--radius);
}
video {
width: 100%;
border-radius: var(--radius);
background: #000;
}
.quiz-wrap {
min-height: 460px;
position: relative;
transition: all 0.25s ease-in;
}
.card {
margin: 0 20px;
padding: 20px;
position: absolute;
left: 0;
right: 0;
background: #fff;
border-radius: 20px;
box-shadow: 0px 10px 20px rgba(0, 0, 0, 0.1);
transition: all 1s cubic-bezier(1, -0.56, 0, 1);
transform: translate3d(0, 0, 0) scale(1);
backface-visibility: hidden;
z-index: 1;
}
.card.drop {
opacity: 0;
transform: translate3d(0, 200px, -20px) scale(0.92);
}
h2 {
font-size: 25px;
text-align: center;
padding-bottom: 20px;
}
.answer {
height: 50px;
line-height: 50px;
font-size: 20px;
display: flex;
text-decoration: none;
border: 1px solid #d5dbdb;
border-radius: 50px;
padding: 0 24px;
margin: 10px 0;
background: #fafafa;
color: #545b64;
transition: all 0.05s ease-in-out;
}
.answer:hover {
background: #ebebebe0;
}
.answer:active {
background: #ff9900;
border: 1px solid #eb5f07;
color: #fff;
}
.answer.correct {
background: #25a702;
border: 1px solid #1d8102;
color: #fff;
animation: blink 0.45s infinite;
}
.answer.wrong {
background: #d13212;
border: 1px solid #b7290d;
color: #fff;
animation: blink 0.45s infinite;
}
#waiting {
top: 100px;
left: 0;
right: 0;
position: absolute;
display: flex;
align-items: center;
}
.waiting-text {
width: 100%;
display: block;
text-align: center;
font-size: 18px;
color: #d5dbdb;
}
.float {
transform: translateY(0px);
animation: float 6s ease-in-out infinite;
}
/* Utility - Position */
.pos-absolute {
position: absolute !important;
}
.pos-fixed {
position: fixed !important;
}
.pos-relative {
position: relative !important;
}
.top-0 {
top: 0 !important;
}
.bottom-0 {
bottom: 0 !important;
}
/* Utility - Width/Height */
.full-width {
width: 100%;
}
.full-height {
height: 100%;
}
/* Animations */
#keyframes blink {
50% {
opacity: 0.8;
}
}
#keyframes float {
0% {
transform: translateY(0px);
}
50% {
transform: translateY(-20px);
}
100% {
transform: translateY(0px);
}
}
/* Mediaqueries */
#media (max-width: 767px) {
h2 {
font-size: 20px;
}
.card {
top: -20px;
}
}
#media (min-width: 767px) {
.card {
top: -25%;
}
}
<head>
<script src="https://content.jwplatform.com/libraries/oH2wJDod.js"></script>
<script src="https://player.live-video.net/1.11.0/amazon-ivs-jw-provider.min.js"></script>
</head>
<body>
<div id="app">
<div class="inner">
<!-- Player wrapper, forcing 16:9 aspect ratio -->
<div class="player-wrapper">
<div class="aspect-spacer"></div>
<div class="pos-absolute full-width full-height top-0">
<div id="video-player"></div>
</div>
</div>
<!-- Quiz UI -->
<div class="quiz-wrap">
<div id="waiting">
<span class="waiting-text float">Waiting for the next question</span>
</div>
<div id="quiz" class="card drop">
<div id="card-inner">
<h2 id="question"></h2>
<div id="answers"></div>
</div>
</div>
</div>
</div>
</div>
</body>
I have a textbox that I would like to do a fancy text slide in/out effect on whenever I change the text in it. I am able to switch the text and trigger the animation and it even works multiple times, but there is a weird jumping into place/resizing of the container div that happens during the animation. I have tried animating the margins of the text elements along with the rest of the animation but that doesn't work. I can't have the div resize because it is contained in a flexbox with an image right below it that I don't want to be pushed out of the way. What can I do to fix this and make the animation smoother?
function textboxWriteAnimated(str) {
const newText = document.createElement('p');
const currentText = document.getElementById("centerText");
const textContainer = document.getElementById("centerTextContainer");
newText.className = "fadingin";
newText.innerHTML = str;
newText.id = "centerText";
currentText.classList.add(["fadingout"]);
textContainer.appendChild(newText);
setTimeout(() => {
textContainer.removeChild(currentText);
document.getElementById("centerText").classList.remove(["fadingin"]);
}, 500)
}
setTimeout(() => {
textboxWriteAnimated("Does it work?");
setTimeout(() => {
textboxWriteAnimated(":(");
}, 1500)
}, 1000)
body, html {
margin: 0;
padding: 0;
overflow: hidden;
}
#vert-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
}
#centerTextContainer {
font-size: 16px;
text-align: center;
line-height: 5px;
margin: 10px;
max-height: 37px;
min-height: 37px;
}
#img-container {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
width: 50vw;
}
#links-container img {
margin: 5px;
}
#keyframes fade-out {
from {
bottom: 0px;
opacity: 100%;
font-size: 16px;
}
to {
bottom: 25px;
opacity: 0%;
font-size: 4px;
}
}
#keyframes fade-in {
from {
top: 25px;
opacity: 0%;
font-size: 4px;
}
to {
top: 0px;
opacity: 100%;
font-size: 16px;
}
}
.fadingout {
animation-name: fade-out;
animation-duration: 500ms;
animation-fill-mode: forwards;
}
.fadingin {
animation-name: fade-in;
animation-duration: 500ms;
}
<div id="vert-container">
<div id="centerTextContainer">
<p id="centerText">Testing...</p>
</div>
<div id="img-container">
<img src="https://img.shields.io/badge/Test-Image-black.svg">
</div>
</div>
Try like this:
function textboxWriteAnimated(str) {
const newText = document.createElement('p');
const currentText = document.getElementById("centerText");
const textContainer = document.getElementById("centerTextContainer");
newText.className = "fadingin";
newText.innerHTML = str;
newText.id = "centerText";
currentText.classList.add(["fadingout"]);
textContainer.appendChild(newText);
setTimeout(() => {
textContainer.removeChild(currentText);
document.getElementById("centerText").classList.remove(["fadingin"]);
}, 500)
}
setTimeout(() => {
textboxWriteAnimated("Does it work?");
setTimeout(() => {
textboxWriteAnimated(":)");
}, 1500)
}, 1000)
body, html {
margin: 0;
padding: 0;
overflow: hidden;
}
#vert-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
}
#centerTextContainer {
font-size: 16px;
text-align: center;
line-height: 5px;
margin: 10px;
max-height: 37px;
min-height: 37px;
position: relative;
display:block;
width:100%;
}
#centerTextContainer > p {
position:absolute;
display:block;
width:100%;
left:0;
right:0;
}
#img-container {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
width: 50vw;
}
#links-container img {
margin: 5px;
}
#keyframes fade-out {
from {
bottom: 0px;
opacity: 100%;
font-size: 16px;
}
to {
bottom: 25px;
opacity: 0%;
font-size: 4px;
}
}
#keyframes fade-in {
from {
top: 25px;
opacity: 0%;
font-size: 4px;
}
to {
top: 0px;
opacity: 100%;
font-size: 16px;
}
}
.fadingout {
animation-name: fade-out;
animation-duration: 500ms;
animation-fill-mode: forwards;
}
.fadingin {
animation-name: fade-in;
animation-duration: 500ms;
}
<div id="vert-container">
<div id="centerTextContainer">
<p id="centerText">Testing...</p>
</div>
<div id="img-container">
<img src="https://img.shields.io/badge/Test-Image-black.svg">
</div>
</div>
The p elements in the animation need absolute positioning so that the top and bottom transitions will work as expected.
I'm using JavaScript to copy all styles of the div#old and use it to the div#young dynamically. I have successful done it, but when I add the transition property, the div#young applies a transition to all styles that I'm copying which I don't want.
Here is my code:
let styles = getComputedStyle(old);
all_style = ['width', 'height', 'background', 'border-radius', 'transition']
for (var i = 0; i < all_style.length; i++) {
young.style.setProperty(`--${all_style[i]}`, styles.getPropertyValue(all_style[i]));
}
.container {
display: flex;
justify-content: space-around;
width: 60%;
}
#old {
width: 110px;
height: 110px;
background: red;
border-radius: 50%;
transition: 1s ease-in-out all;
}
#young {
width: var(--width);
height: var(--height);
background: var(--background);
border-radius: var(--border-radius);
transition: var(--transition);
}
<div class="container">
<div id="old"></div>
<div id="young"></div>
</div>
In summary I don't want the transition on border-radius of div#young and the reason why I'm adding transition is for my animation, so to remove it won't answer my question.
make 0 the transition you don't want to happen. The order is important, the all need to be the first one:
let styles = getComputedStyle(old);
all_style = ['width', 'height', 'background', 'border-radius', 'transition']
for (var i = 0; i < all_style.length; i++) {
young.style.setProperty(`--${all_style[i]}`, styles.getPropertyValue(all_style[i]));
}
.container {
display: flex;
justify-content: space-around;
width: 60%;
}
#old {
width: 110px;
height: 110px;
background: red;
border-radius: 50%;
transition: 1s ease-in-out all,border-radius 0s;
}
#young {
width: var(--width);
height: var(--height);
background: var(--background);
border-radius: var(--border-radius);
transition: var(--transition);
}
<div class="container">
<div id="old"></div>
<div id="young"></div>
</div>
If you don't want any you can update the display value after the styles copy.
let styles = getComputedStyle(old);
all_style = ['width', 'height', 'background', 'border-radius', 'transition']
for (var i = 0; i < all_style.length; i++) {
young.style.setProperty(`--${all_style[i]}`, styles.getPropertyValue(all_style[i]));
}
young.style.display="initial"
.container {
display: flex;
justify-content: space-around;
width: 60%;
}
#old {
width: 110px;
height: 110px;
background: red;
border-radius: 50%;
transition: 1s ease-in-out all;
}
#young {
width: var(--width);
height: var(--height);
background: var(--background,none);
border-radius: var(--border-radius);
transition: var(--transition);
display:none;
}
<div class="container">
<div id="old"></div>
<div id="young"></div>
</div>
Add the transition with very little delay.
let styles = getComputedStyle(old);
all_style = ['width', 'height', 'background', 'border-radius', 'transition']
for (var i = 0; i < all_style.length; i++) {
if (all_style[i] !== 'transition') {
young.style.setProperty(`--${all_style[i]}`, styles.getPropertyValue(all_style[i]));
} else {
setTimeout(() => {
young.style.setProperty(`--${all_style[i]}`, styles.getPropertyValue(all_style[i]));
}, 10); // 1 second / 100
}
}
.container {
display: flex;
justify-content: space-around;
width: 60%;
}
#old {
width: 110px;
height: 110px;
background: red;
border-radius: 50%;
transition: 1s ease-in-out all;
}
#young {
width: var(--width);
height: var(--height);
background: var(--background);
border-radius: var(--border-radius);
transition: var(--transition);
}
<div class="container">
<div id="old"></div>
<div id="young"></div>
</div>