I'm working on a project where a video plays in the background and events need to be fired at certain points in the video. At these points, the video needs to gradually slow down and stop before the event displays.
So far I have made this happen by getting the frame rate and the more it goes up the slower the video playback is, however, it is quite stuttery and jumps into slowing down very fast I would like something smoother. Also currently when you then want to replay the video it falls within the slow down to a stop area of the frames and starts to slow down before starting to play again. I've put in a different video to my actual video as for demo purposes so there is only one event which actually fires in this due to the video being small but there's need to be multiple events at different points in the video.
var currentFrame = $('#currentFrame');
var video = VideoFrame({
id: 'video',
frameRate: 29.97,
callback: function(frame) {
currentFrame.html(frame);
if ((frame > 60) && (frame < 135) || (frame > 875) && (frame < 952) || (frame > 1700) && (frame < 1798)) {
decrease_rate(frame);
} else {
reset_frames_rate();
}
}
});
$('#play-pause').click(function() {
ChangeButtonText();
});
window.decrease_rate = decrease_rate;
var frame_on_start = 0,
frame_rate_dif,
new_speed;
function decrease_rate(frame) {
if (frame_on_start == 0) {
console.log("frame rate reset");
frame_on_start = frame;
} else {
frame_rate_dif = frame - frame_on_start;
new_speed = 1 - (frame_rate_dif / 100);
document.querySelector('video').playbackRate = new_speed;
if (frame_rate_dif > 65) {
reset_frames_rate();
video.video.pause();
video.stopListen();
$("#play-pause").html('Play');
show_event();
}
}
}
window.show_event = show_event;
function show_event() {
$('.event1').removeClass('hide_event');
}
window.reset_frames_rate = reset_frames_rate;
function reset_frames_rate() {
frame_on_start = 0;
frame_rate_dif = 0;
document.querySelector('video').playbackRate = 1;
}
function ChangeButtonText() {
if (video.video.paused) {
video.video.play();
video.listen('frame');
$("#play-pause").html('Pause');
$('.event1').addClass('hide_event');
} else {
video.video.pause();
video.stopListen();
$("#play-pause").html('Play');
}
}
#container {
position: relative;
}
.hide_event {
display: none;
}
.event1 {
position: absolute;
top: 40%;
left: 0px;
background-color: white;
width: 100%;
text-align: center;
}
<script src="https://rawgit.com/allensarkisyan/VideoFrame/master/VideoFrame.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<video height="180" width="100%" id="video">
<source src="http://www.w3schools.com/html/mov_bbb.mp4"></source>
</video>
<div id="event1" class="event1 hide_event">
<p>Display event</p>
</div>
</div>
<div class="frame">
<span id="currentFrame">0</span>
</div>
<div id="controls">
<button id="play-pause">Play</button>
</div>
Related
I use the isInViewport script to play the video on scroll, but it doesn't look very good because it happens multiple times. Please tell how to limit the triggering of animation or video playback to literally once. Tried to add with one() and true/false but the code didn't work (I still green in jquery).
<div class="block"><span>Video below</span></div>
<div class="block video-block">
<video class="video" loop="loop" width="640" controls="controls" muted>
<source src="http://denis-creative.com/wp-content/uploads/2018/01/video.mp4" type="video/mp4" />
<source src="http://denis-creative.com/wp-content/uploads/2018/01/video.ogv" type="video/ogv" />
<source src="http://denis-creative.com/wp-content/uploads/2018/01/video.webm" type="video/webm" />
</video>
</div>
<div class="block"><span>Video above</span></div>
.block{
height: 100vh;
font-size: 60px;
text-align: center;
display: flex;
}
.block > *{
margin: auto;
display: inline-block;
max-width: 100%;
}
// Plugin isInViewport
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(require("jquery"),require("window")):"function"==typeof define&&define.amd?define("isInViewport",["jquery","window"],n):n(e.$,e.window)}(this,function(e,n){"use strict";function t(n){var t=this;if(1===arguments.length&&"function"==typeof n&&(n=[n]),!(n instanceof Array))throw new SyntaxError("isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions");return n.forEach(function(n){"function"!=typeof n?(console.warn("isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions"),console.warn("isInViewport: Ignoring non-function values in array and moving on")):[].slice.call(t).forEach(function(t){return n.call(e(t))})}),this}function o(n){var t=e("<div></div>").css({width:"100%"});n.append(t);var o=n.width()-t.width();return t.remove(),o}function r(t,i){var a=t.getBoundingClientRect(),u=a.top,c=a.bottom,f=a.left,l=a.right,d=e.extend({tolerance:0,viewport:n},i),s=!1,p=d.viewport.jquery?d.viewport:e(d.viewport);p.length||(console.warn("isInViewport: The viewport selector you have provided matches no element on page."),console.warn("isInViewport: Defaulting to viewport as window"),p=e(n));var w=p.height(),h=p.width(),v=p[0].toString();if(p[0]!==n&&"[object Window]"!==v&&"[object DOMWindow]"!==v){var g=p[0].getBoundingClientRect();u-=g.top,c-=g.top,f-=g.left,l-=g.left,r.scrollBarWidth=r.scrollBarWidth||o(p),h-=r.scrollBarWidth}return d.tolerance=~~Math.round(parseFloat(d.tolerance)),d.tolerance<0&&(d.tolerance=w+d.tolerance),l<=0||f>=h?s:s=d.tolerance?u<=d.tolerance&&c>=d.tolerance:c>0&&u<=w}function i(n){if(n){var t=n.split(",");return 1===t.length&&isNaN(t[0])&&(t[1]=t[0],t[0]=void 0),{tolerance:t[0]?t[0].trim():void 0,viewport:t[1]?e(t[1].trim()):void 0}}return{}}e="default"in e?e.default:e,n="default"in n?n.default:n,/**
* #author Mudit Ameta
* #license https://github.com/zeusdeux/isInViewport/blob/master/license.md MIT
*/
e.extend(e.expr[":"],{"in-viewport":e.expr.createPseudo?e.expr.createPseudo(function(e){return function(n){return r(n,i(e))}}):function(e,n,t){return r(e,i(t[3]))}}),e.fn.isInViewport=function(e){return this.filter(function(n,t){return r(t,e)})},e.fn.run=t});
//# isInViewport
// Play Video
$(function() {
var $video = $('.video');
var $window = $(window);
$window.scroll(function() {
if ($video.is(":in-viewport")) {
$video[0].play();
} else {
$video[0].pause();
}
});
});
You could add a var to check if the video is still playing (for example is_playing) and check it with an inner if:
$(function() {
var $video = $('.video');
var $window = $(window);
var is_playing = false;
$window.scroll(function() {
if ($video.is(":in-viewport")) {
if (!is_playing) {
is_playing = true;
$video[0].play();
}
} else {
$video[0].pause();
}
});
});
This is a very simple browser memory game which you need to to flip all the matched cards in order to win.
The bug :
In the game if you click fast enough you can flip more than 2 cards.
I've tried a lot to fix it but couldn't figure it out by myself. I would appreciate any help in solving this issue as I am new to JavaScript and it's still hard for me fix those basic bugs.
Game files:
HTML:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My App</title>
<link rel="stylesheet" href="css/game.css" />
</head>
<body>
<button class="Change User" onclick="change(this)">Change User</button>
<div class="header">
<img src="img/layout/logo.png">
<h1>Memory Monsters</h1>
<p id="Play Again"></p>
</div>
<div class="card" data-card="1" onclick="cardClicked(this)">
<img src="img/cards/1.png">
<img class="back" src="img/cards/back.png">
</div>
<div class="card" data-card="7" onclick="cardClicked(this)">
<img src="img/cards/7.png">
<img class="back" src="img/cards/back.png">
</div>
<div class="card" data-card="1" onclick="cardClicked(this)">
<img src="img/cards/1.png">
<img class="back" src="img/cards/back.png">
</div>
<div class="card" data-card="7" onclick="cardClicked(this)">
<img src="img/cards/7.png">
<img class="back" src="img/cards/back.png">
</div>
<div class="card" data-card="5" onclick="cardClicked(this)">
<img src="img/cards/5.png">
<img class="back" src="img/cards/back.png">
</div>
<div class="card" data-card="5" onclick="cardClicked(this)">
<img src="img/cards/5.png">
<img class="back" src="img/cards/back.png">
</div>
<script src="js/game.js"></script>
</body>
</html>
javascript:
var getElementsByClassName = prompt ('What is your name?');
window.localStorage.setItem ('name', 'dan');
function change(username) {
prompt('What is your name?');
}
// Those are global variables, they stay alive and reflect the state of the game
var elPreviousCard = null;
var flippedCouplesCount = 0;
// This is a constant that we dont change during the game (we mark those with CAPITAL letters)
var TOTAL_COUPLES_COUNT = 3;
// Load an audio file
var audioWin = new Audio('sound/win.mp3');
// This function is called whenever the user click a card
function cardClicked(elCard) {
// If the user clicked an already flipped card - do nothing and return from the function
if (elCard.classList.contains('flipped')) {
return;
}
// Flip it
elCard.classList.add('flipped');
// This is a first card, only keep it in the global variable
if (elPreviousCard === null) {
elPreviousCard = elCard;
} else {
// get the data-card attribute's value from both cards
var card1 = elPreviousCard.getAttribute('data-card');
var card2 = elCard.getAttribute('data-card');
// No match, schedule to flip them back in 1 second
if (card1 !== card2){
setTimeout(function () {
elCard.classList.remove('flipped');
elPreviousCard.classList.remove('flipped');
elPreviousCard = null;
}, 1000)
} else {
// Yes! a match!
flippedCouplesCount++;
elPreviousCard = null;
// All cards flipped!
if (TOTAL_COUPLES_COUNT === flippedCouplesCount) {
audioWin.play();
// and finally add a button to call resetCard()
document.getElementById("Play Again").innerHTML =
'<button onclick="resetCard();">Play Again</button>';
}
}
}
}
function resetCard() {// to erase the flipped classes
var cardclass = document.getElementsByClassName("card");
for (i = 0; i < cardclass.length; i++) {
cardclass[i].classList.remove("flipped");
document.getElementById("Play Again").innerHTML = "";
}
}
CSS:
.header {
background-color: lightblue;
padding: 20px;
border-bottom: 10px solid darkcyan;
color:darkcyan;
font-size: 1.5em;
text-align: center;
}
.header img {
float:right;
}
.card {
background-color: pink;
height: 165px;
width: 165px;
float: left;
margin: 5px;
}
.card img {
position: absolute;
}
.flipped .back {
display: none;
}
i made a game like this. you need to create a variable that starts on 0
let tries = 0;
then add one to it each time a card is selected. make sure to not allow it to count if a card that is already flipped is clicked again. here is some of the code from the function that is run on my onclick. I am using a React framework, but if you write this logic in your JS function, it is what you will need to make it work
selected = (event) => {
if (canClick === true) {
let id = event.currentTarget.id; //card0
let idString = id.toString(); //"card0"
//ONLY ALLOW A CARD TO BE CLICKED IF ITS FACE DOWN
if (this.state[idString] === cardBack) {
idString = idString.replace(/card/g, ''); //"0"
this.setState({[id] : arrayRandom[idString]});
//FIRST PICK
if (counter % 2 == 1) {
curCard1 = arrayRandom[idString].toString();
id1 = id;
counter++;
//SECOND PICK
} else {
//MAKE SURE A CARD DOESN'T GET SELECTED TWICE IN A ROW AND STAY FACE UP
if (id === id1) {
console.log("Select a different card for your second pick");
} else {
counter++;
tries++;
canClick = false; //STOP USER FROM SELECTING ANOTHER CARD
curCard2 = arrayRandom[idString].toString();
id2 = id;
setTimeout(() => {canClick = true}, 1000); //USER CAN PICK AGAIN IN 1 SEONCD
//IF THERE'S A MATCH - CARDS STAY FLIPPED, SCORE INCREASES BY 1
if (curCard1 == curCard2) {
score = score + 1;
//IF THERE'S NO MATCH - CARDS FLIP FACE DOWN AFTER A SECOND
} else {
setTimeout(() => {
this.setState({[id1]: cardBack});
this.setState({[id2]: cardBack});
}, 1000);
}
}
}
} else {
console.log("This card has already been flipped, select another one");
}
}
}
here is my game
https://reactcardmatch.netlify.com/
I have a video tag say
<div class="phone" align="center">
<div class="phone-inner">
<video width="100%" height="100%" autoplay="" loop="" muted id="phonevideo">
<source src="vid/1.mp4" type="video/mp4">
</video>
</div>
</div>
I want to change the video when page scrolls and each time div changes like fueled.com. Say I have six divisions like
<div id="first></div>
<div id="two"></div>
<div id="three"></div>
<div id="four"></div>
<div id="five"></div>
<div id="six"></div>
When div 2 comes into view the video should change and when div 3 or 4 comes into view video should change again to something else. Here is my code which needs to be modified according to it.
$(window).scroll(function() {
var topDivHeight = $("#first").height();
var DivTop = $("#sixth").position().top;
var viewPortSize = $(window).height();
var triggerAt = 450;
var triggerHeight = (topDivHeight - viewPortSize) + triggerAt;
var test1 = (topDivHeight - viewPortSize) + 650;
var count = 0;
var number = jQuery.grep(mainTops, function(n, i) {
if (n < $(window).scrollTop())
{
count++;
}
});
$('.nav ul li a').css("color", "#fff");
$('.nav ul li a#nav'+count ).css("color", "#f60");
if($(window).scrollTop() >= triggerHeight && $(window).scrollTop() < DivTop) {
$('.phone').css('visibility', 'visible').fadeIn();
if($(window).scrollTop() >= test1){
$('#phonevideo').html('<source src="vid/2.mp4" type="video/mp4">'); // tried using this method but its not working here. Some other method needed here.
}
} else {
$('.phone').fadeOut();
}
});
Try this code:
$('#phonevideo').find("source").attr("src", "https://www.w3schools.com/tags/movie.mp4");
$('#phonevideo').get(0).load();
You can change source attribute like $('#phonevideo').find("source").attr("src","videosource")
and after changing source you need to load video $('#phonevideo').get(0).load()
You cannot directly replace the HTML as you do using function .html(), accordingly to the HTML specification
Dynamically modifying a source element and its attribute when the
element is already inserted in a video or audio element will have no
effect.
But what you can try as suggested by the document is to change what is playing, just use the src attribute on the media element directly and use function .load();
A working example below:
var btn = document.getElementById('btn'),
player = document.getElementById('phonevideo'),
source = document.getElementById('src');
btn.addEventListener('click', function(event) {
player.pause();
source.src = 'http://html5demos.com/assets/dizzy.mp4'; // change video
player.load(); // load it
});
<div class="phone" align="center">
<div class="phone-inner">
<video width="100%" height="100%" autoplay="" loop="" muted id="phonevideo">
<source id="src" src="http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4" type="video/mp4">
</video>
</div>
</div>
<button id="btn" type="button">Change Video!</button>
Using jQuery as on your example (not tested):
var player = $('#phonevideo');
player.find("source").attr("src", "http://html5demos.com/assets/dizzy.mp4");
player[0].load();
I've optimized your code. I have added a class to your divs and used the data attribute. Here is a working jsfiddle.
<div class="phone" align="center">
<div class="phone-inner">
<video width="100%" height="100%" autoplay="" loop="" muted id="phonevideo">
<source src="vid/1.mp4" type="video/mp4">
</video>
</div>
</div>
<div id="first" class="view" data-vid-src="vid/1.mp4"></div>
<div id="two" class="view" data-vid-src="vid/2.mp4"></div>
<div id="three" class="view" data-vid-src="vid/3.mp4"></div>
<div id="four" class="view" data-vid-src="vid/4.mp4"></div>
<div id="five" class="view" data-vid-src="vid/5.mp4"></div>
<div id="six" class="view" data-vid-src="vid/6.mp4"></div>
To see some result I have added some css:
.phone {
position: fixed;
height: 200px;
width: 120px;
background: white;
top: 50%;
left: 50%;
margin-top: -100px;
margin-left: -60px;
}
.view {
height: 500px;
}
#first {
background: red;
}
#two {
background: yellow;
}
#three {
background: green;
}
#four {
background: blue;
}
#five {
background: pink;
}
#six {
background: black;
}
And now the jQuery part.
function getCurrentElement(pos) {
var len = $('.view').length;
var i = 0;
var old_pos;
var ele_pos;
var old_ele;
var return_ele;
$('.view').each(function(){
i++;
offset = $(this).offset();
ele_pos = offset.top;
if(pos == ele_pos) {
return_ele = $(this);
return;
}
else if(ele_pos > pos && old_pos < pos) {
return_ele = old_ele;
return;
}
else if(ele_pos < pos && i == len) {
return_ele = $(this);
return;
}
old_pos = ele_pos;
old_ele = $(this);
});
return return_ele;
}
var old_ele = null;
$(window).scroll(function() {
var cur_pos = $(window).scrollTop();
current_element = getCurrentElement(cur_pos);
if(old_ele != null) {
if(current_element.attr('id') != old_ele.attr('id')) {
$('#phonevideo source').attr('src',current_element.attr('data-vid-src'))
}
}
old_ele = current_element;
});
I hope this code will help you. :)
In my webpage I have 4 "waypoints" that have their respective links in a menu. What I need is to also bind the scroll of the page to these waypoints. So when the page loads, the pointer is at the top and based on the scrolling direction, the page moves to the next/previous waypoint. Until now I have come up with this simplistic approach, which goes into a scroll loop due to the scrollTo() function triggering the whole method again.
$(function () {
var top = $(window).scrollTop();
var currentWaypoint = 0;
var previousWaypoint = 0;
$(window).scroll(function () {
console.log("Scroll triggered");
console.log("Current Waypoint: " + currentWaypoint);
var curTop = $(window).scrollTop();
if (top < curTop) {
if (currentWaypoint < 4) {
previousWaypoint = currentWaypoint;
currentWaypoint=currentWaypoint+1;
}
}
else {
if (currentWaypoint > 0) {
previousWaypoint = currentWaypoint;
currentWaypoint=currentWaypoint-1;
}
}
top = curTop;
if (previousWaypoint != currentWaypoint) {
switch (currentWaypoint) {
case 1:
$.scrollTo(document.getElementById("waypoint-collection"));
case 2:
$.scrollTo(document.getElementById("waypoint-report"));
case 3:
$.scrollTo(document.getElementById("waypoint-video"));
case 4:
$.scrollTo(document.getElementById("waypoint-mail"));
default:
}
}
console.log("New Waypoint: " + currentWaypoint);
});
});
I've seen this sort of behaviour implemented in some websites but cannot seem to find anything relevant with google. Any ideas?
EDIT:
The relevant HTML code:
<html>
<head>
<style>
body {
background-color: #FFFFFF;
}
.features-container-wh {
min-height: 12.5rem;
text-align: center;
height: 100%;
}
.features-container-bl {
background-color: #43bfcb;
text-align: center;
color: #FFFFFF;
height: 100%;
}
.features-container-bottom {
height: 100%;
}
</style>
</head>
<body>
<div class="features-container-wh">
Collection
Report
Video
Mail
</div>
<div class="features-container-bl" id="waypoint-collection">
<p>Stuff...</p>
</div>
<div class="features-container-wh" id="waypoint-report">
<p>Stuff...</p>
</div>
<div class="features-container-bl" id="waypoint-video">
<p>Stuff...</p>
</div>
<div class="features-container-bottom" id="waypoint-mail">
<p>Stuff...</p>
</div>
</body>
$('html, body').animate({scrollTop: $("#.wayPoint1").offset().top}, 2000);
I am new person in Front End Development and i am facing one major problem is that i have 3 images placed on each others and now i want to move one image so the other image comes up and then it goes and third image comes up after some interval of time.
I want three images on same position in my site but only wants to see these three images one after one after some interval of time.
Please help how i can do this??
May i use marquee property or javascript???
Non-jQuery Option
If you don't want to go down the jquery route, you can try http://www.menucool.com/javascript-image-slider. The setup is just as easy, you just have to make sure that your images are in a div with id of slider and that div has the same dimensions as one of your images.
jQuery Option
The jQuery cycle plugin will help you achieve this. It requires jquery to work but it doesn't need much setting up to create a simple sliple slideshow.
Have a look at the 'super basic' demo:
$(document).ready(function() {
$('.slideshow').cycle({
fx: 'fade' // choose your transition type, ex: fade, scrollUp, shuffle, etc...
});
});
It has many options if you want something a bit fancier.
Here you go PURE JavaScript solution:
EDIT I have added image rotation... Check out live example (link below)
<script>
var current = 0;
var rotator_obj = null;
var images_array = new Array();
images_array[0] = "rotator_1";
images_array[1] = "rotator_2";
images_array[2] = "rotator_3";
var rotate_them = setInterval(function(){rotating()},4000);
function rotating(){
rotator_obj = document.getElementById(images_array[current]);
if(current != 0) {
var rotator_obj_pass = document.getElementById(images_array[current-1]);
rotator_obj_pass.style.left = "-320px";
}
else {
rotator_obj.style.left = "-320px";
}
var slideit = setInterval(function(){change_position(rotator_obj)},30);
current++;
if (current == images_array.length+1) {
var rotator_obj_passed = document.getElementById(images_array[current-2]);
rotator_obj_passed.style.left = "-320px";
current = 0;
rotating();
}
}
function change_position(rotator_obj, type) {
var intleft = parseInt(rotator_obj.style.left);
if (intleft != 0) {
rotator_obj.style.left = intleft + 32 + "px";
}
else if (intleft == 0) {
clearInterval(slideit);
}
}
</script>
<style>
#rotate_outer {
position: absolute;
top: 50%;
left: 50%;
width: 320px;
height: 240px;
margin-top: -120px;
margin-left: -160px;
overflow: hidden;
}
#rotate_outer img {
position: absolute;
top: 0px;
left: 0px;
}
</style>
<html>
<head>
</head>
<body onload="rotating();">
<div id="rotate_outer">
<img src="0.jpg" id="rotator_1" style="left: -320px;" />
<img src="1.jpg" id="rotator_2" style="left: -320px;" />
<img src="2.jpg" id="rotator_3" style="left: -320px;" />
</div>
</body>
</html>
And a working example:
http://simplestudio.rs/yard/rotate/rotate.html
If you aim for good transition and effect, I suggest an image slider called "jqFancyTransitions"
<html>
<head>
<script type="text/javascript">
window.onload = function(){
window.displayImgCount = 0;
function cycleImage(){
if (displayImgCount !== 0) {
document.getElementById("img" + displayImgCount).style.display = "none";
}
displayImgCount = displayImgCount === 3 ? 1 : displayImgCount + 1;
document.getElementById("img" + displayImgCount).style.display = "block";
setTimeout(cycleImage, 1000);
}
cycleImage();
}
</script>
</head>
<body>
<img id="img1" src="./img1.png" style="display: none">
<img id="img2" src="./img2.png" style="display: none">
<img id="img3" src="./img3.png" style="display: none">
</body>
</html>
Fiddle: http://jsfiddle.net/SReject/F7haV/
arrayImageSource= ["Image1","Image2","Image3"];
setInterval(cycle, 2000);
var count = 0;
function cycle()
{
image.src = arrayImageSource[count]
count = (count === 2) ? 0 : count + 1;
}
Maybe something like this?