Play HTML5 Video when scrolled to - javascript

Is there anyway to autoplay a HTML5 video only when the user has the video (or a certain percentage of the video) in the browser viewport?

In brief
Let's say our browser window W currently scrolled to y-position scrollTop and scrollBottom
Our video will NOT be played when its position is at V1 or V2 as below snapshot.
Code details
$(document).ready(function() {
// Get media - with autoplay disabled (audio or video)
var media = $('video').not("[autoplay='autoplay']");
var tolerancePixel = 40;
function checkMedia(){
// Get current browser top and bottom
var scrollTop = $(window).scrollTop() + tolerancePixel;
var scrollBottom = $(window).scrollTop() + $(window).height() - tolerancePixel;
media.each(function(index, el) {
var yTopMedia = $(this).offset().top;
var yBottomMedia = $(this).height() + yTopMedia;
if(scrollTop < yBottomMedia && scrollBottom > yTopMedia){ //view explaination in `In brief` section above
$(this).get(0).play();
} else {
$(this).get(0).pause();
}
});
//}
}
$(document).on('scroll', checkMedia);
});

hope this helps but it has been answered before
http://jsfiddle.net/jAsDJ/
var videos = document.getElementsByTagName("video"),
fraction = 0.8;
function checkScroll() {
for(var i = 0; i < videos.length; i++) {
var video = videos[i];
var x = video.offsetLeft, y = video.offsetTop, w = video.offsetWidth, h = video.offsetHeight, r = x + w, //right
b = y + h, //bottom
visibleX, visibleY, visible;
visibleX = Math.max(0, Math.min(w, window.pageXOffset + window.innerWidth - x, r - window.pageXOffset));
visibleY = Math.max(0, Math.min(h, window.pageYOffset + window.innerHeight - y, b - window.pageYOffset));
visible = visibleX * visibleY / (w * h);
if (visible > fraction) {
video.play();
} else {
video.pause();
}
}
}
window.addEventListener('scroll', checkScroll, false);
window.addEventListener('resize', checkScroll, false);

You can use window.pageXOffset and window.pageYOffset to check how far your browser window is scrolled both vertically and horizontally. Use these with window.innerWidth and innerHeight and some basic geometry math to calculate how much your visible page overlaps with the video itself. Put this all in a function that you can attach to the scroll and resize event on the window object to run the check every time the scrolling changes.
Here is some sample code:
var video = document.getElementById('video'),
info = document.getElementById('info'),
fraction = 0.8;
function checkScroll() {
var x = video.offsetLeft,
y = video.offsetTop,
w = video.offsetWidth,
h = video.offsetHeight,
r = x + w, //right
b = y + h, //bottom
visibleX,
visibleY,
visible;
if (window.pageXOffset >= r ||
window.pageYOffset >= b ||
window.pageXOffset + window.innerWidth < x ||
window.pageYOffset + window.innerHeight < y
) {
info.innerHTML = '0%';
return;
}
visibleX = Math.max(0, Math.min(w, window.pageXOffset + window.innerWidth - x, r - window.pageXOffset));
visibleY = Math.max(0, Math.min(h, window.pageYOffset + window.innerHeight - y, b - window.pageYOffset));
visible = visibleX * visibleY / (w * h);
info.innerHTML = Math.round(visible * 100) + '%';
if (visible > fraction) {
video.play();
} else {
video.pause();
}
}
window.addEventListener('scroll', checkScroll, false);
window.addEventListener('resize', checkScroll, false);
//one time at the beginning, in case it starts in view
checkScroll();
//as soon as we know the video dimensions
video.addEventListener('loadedmetadata', checkScroll, false);
And a working example.
This code assumes a pretty simple page layout. If your video is positioned absolutely inside another element that has "position: relative" set, then you'll need to do a little more work to calculate the correct position of the video. (The same goes if the video has been moved with CSS transforms.)

There is a new API for this scenario, called Intersection_Observer_API, which
Chrome 51+ and Edge 15+ has supported.
var options = {
root: document.querySelector('.scroll-container'),
rootMargin: '0px',
threshold: 1.0 // trigger only when element comes into view completely
};
var ob = new IntersectionObserver((entries, observer) => {
entries[0].target.classList.toggle('red');
}, options);
// observe all targets, when coming into view, change color
document.querySelectorAll('.target').forEach((item) => {
ob.observe(item);
});
Here is a simple demo:
https://codepen.io/hectorguo/pen/ybOKEJ

This pure javascript solution worked for me:
// is visible function
function isVisible(elem) {
if (!(elem instanceof Element)) throw Error('DomUtil: elem is not an element.');
const style = getComputedStyle(elem);
if (style.display === 'none') return false;
if (style.visibility !== 'visible') return false;
if (style.opacity < 0.1) return false;
if (elem.offsetWidth + elem.offsetHeight + elem.getBoundingClientRect().height +
elem.getBoundingClientRect().width === 0) {
return false;
}
const elemCenter = {
x: elem.getBoundingClientRect().left + elem.offsetWidth / 2,
y: elem.getBoundingClientRect().top + elem.offsetHeight / 2
};
if (elemCenter.x < 0) return false;
if (elemCenter.x > (document.documentElement.clientWidth || window.innerWidth)) return false;
if (elemCenter.y < 0) return false;
if (elemCenter.y > (document.documentElement.clientHeight || window.innerHeight)) return false;
let pointContainer = document.elementFromPoint(elemCenter.x, elemCenter.y);
do {
if (pointContainer === elem) return true;
} while (pointContainer = pointContainer.parentNode);
return false;
}
// on window load start checking on scroll
window.onload = function() {
var videos = document.getElementsByTagName("video")
function checkScroll() {
for(var i = 0; i < videos.length; i++) {
var video = videos[i];
if(isVisible(video)){
video.play();
}else{
video.pause()
}
}
}
window.addEventListener('scroll', checkScroll, false);
window.addEventListener('resize', checkScroll, false);
}
isVisible function is from other solution: answer for checking visible elements on stackoverflow

Related

Mousewheel smooth scroll

I'm looking for make a smooth scroll effect in my website, like these websites :
http://www.femmefatale.paris/fr/project/tati-express
http://onirim.com/photographers/olaf-wipperfurth/
I only found this script : https://github.com/fatlinesofcode/jquery.smoothwheel
But it doesn't work when you scroll your page in holding the scrollbar...
Here's my code I apply at the body :
https://jsfiddle.net/bLhs0fkn/1/
(function ($) {
var self = this, container, running=false, currentY = 0, targetY = 0, oldY = 0, maxScrollTop= 0, minScrollTop, direction, onRenderCallback=null,
fricton = 0.95, // higher value for slower deceleration
vy = 0,
stepAmt = 0.8,
minMovement= 0.3,
ts=0.1;
var updateScrollTarget = function (amt) {
targetY += amt;
vy += (targetY - oldY) * stepAmt;
oldY = targetY;
}
var render = function () {
if (vy < -(minMovement) || vy > minMovement) {
currentY = (currentY + vy);
if (currentY > maxScrollTop) {
currentY = vy = 0;
} else if (currentY < minScrollTop) {
vy = 0;
currentY = minScrollTop;
}
container.scrollTop(-currentY);
vy *= fricton;
// vy += ts * (currentY-targetY);
// scrollTopTweened += settings.tweenSpeed * (scrollTop - scrollTopTweened);
// currentY += ts * (targetY - currentY);
if(onRenderCallback){
onRenderCallback();
}
}
}
var animateLoop = function () {
if(! running)return;
requestAnimFrame(animateLoop);
render();
//log("45","animateLoop","animateLoop", "",stop);
}
var onWheel = function (e) {
e.preventDefault();
var evt = e.originalEvent;
var delta = evt.detail ? evt.detail * -1 : evt.wheelDelta / 40;
var dir = delta < 0 ? -1 : 1;
if (dir != direction) {
vy = 0;
direction = dir;
}
//reset currentY in case non-wheel scroll has occurred (scrollbar drag, etc.)
currentY = -container.scrollTop();
updateScrollTarget(delta);
}
/*
* http://paulirish.com/2011/requestanimationframe-for-smart-animating/
*/
window.requestAnimFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
/*
* http://jsbin.com/iqafek/2/edit
*/
var normalizeWheelDelta = function () {
// Keep a distribution of observed values, and scale by the
// 33rd percentile.
var distribution = [], done = null, scale = 30;
return function (n) {
// Zeroes don't count.
if (n == 0) return n;
// After 500 samples, we stop sampling and keep current factor.
if (done != null) return n * done;
var abs = Math.abs(n);
// Insert value (sorted in ascending order).
outer: do { // Just used for break goto
for (var i = 0; i < distribution.length; ++i) {
if (abs <= distribution[i]) {
distribution.splice(i, 0, abs);
break outer;
}
}
distribution.push(abs);
} while (false);
// Factor is scale divided by 33rd percentile.
var factor = scale / distribution[Math.floor(distribution.length / 3)];
if (distribution.length == 500) done = factor;
return n * factor;
};
}();
$.fn.smoothWheel = function () {
// var args = [].splice.call(arguments, 0);
var options = jQuery.extend({}, arguments[0]);
return this.each(function (index, elm) {
if(!('ontouchstart' in window)){
container = $(this);
container.bind("mousewheel", onWheel);
container.bind("DOMMouseScroll", onWheel);
//set target/old/current Y to match current scroll position to prevent jump to top of container
targetY = oldY = container.get(0).scrollTop;
currentY = -targetY;
minScrollTop = container.get(0).clientHeight - container.get(0).scrollHeight;
if(options.onRender){
onRenderCallback = options.onRender;
}
if(options.remove){
log("122","smoothWheel","remove", "");
running=false;
container.unbind("mousewheel", onWheel);
container.unbind("DOMMouseScroll", onWheel);
}else if(!running){
running=true;
animateLoop();
}
}
});
};
})(jQuery);
Thanks
The problem with your code is that you are trying to apply smoothWheel to your DOM body. What you can do instead is wrap all the div inside another div (id="wrapper") and apply the CSS and JS onto this div.
HTML
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js" type="text/javascript"></script>
<script src="http://fatlinesofcode.github.io/jquery.smoothwheel/src/jquery.smoothwheel.js" type="text/javascript"></script>
<div id="wrapper">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</body>
JS
$(document).ready(function(){//alert('1')
$("#wrapper").smoothWheel();
});
CSS
#wrapper {
height:300px;
width:100%;
overflow:auto;
-webkit-overflow-scrolling: touch;
background: grey;
}
div {
height:100px;
width:100px;
background:lightblue;
margin-bottom : 50px;
}
Here is a Demo for the same.

When the cursor leaves the screen, the game doesn't end in Javascript

The link to my code in CodePen - http://codepen.io/PartTimeCoder/pen/RaMZop?editors=0010
The Javascript is below, in the increase function there is an if command that should prevent the user's mouse from leaving the screen, but it doesn't work. Also, right when the page loads it should start adding the score, but instead it only starts after a click. I don't see any reason for this to happen:
$(document).ready(function() {
var canvas = document.getElementById("canvas")
var ctx = canvas.getContext("2d")
var height = window.innerHeight
var width = window.innerWidth
var mouse = {};
var hover;
var redDots = 2;
var score = 0;
canvas.width = width
canvas.height = height
var circle_count = 10;
var circles = [];
var generate = function() {
for (var i = 0; i < circle_count; i++) {
circles.push(new circle());
}
}
setInterval(generate, 100);
canvas.addEventListener('mousedown', mousePos, false);
canvas.addEventListener('touch', mousePos, false);
function mousePos(e) {
mouse.x = e.pageX;
mouse.y = e.pageY;
}
function circle() {
this.speed = {
x: 2.5 + Math.random() * 5,
y: 2.5 + Math.random() * 5
}
this.location = {
x: 0 - Math.random() * width,
y: 0 - Math.random() * height
}
this.accel = {
x: -1.5 + Math.random() * 3,
y: -1.5 + Math.random() * 3
}
this.radius = 5 + Math.random() * 10
}
var draw = function() {
ctx.globalCompositeOperation = "source-over";
ctx.fillStyle = "black";
ctx.fillRect(0, 0, width, height);
ctx.globalCompositeOperation = "lighter";
for (var i = 0; i < circles.length; i++) {
var c = circles[i];
ctx.beginPath();
ctx.fillStyle = "red";
ctx.arc(c.location.x, c.location.y, c.radius, Math.PI * 2, false);
ctx.fill();
c.speed.x += c.accel.x;
c.speed.y += c.accel.y;
c.location.x += c.speed.x;
c.location.y += c.speed.y;
if (mouse.x > c.location.x - c.radius && mouse.x < c.location.x + c.radius && mouse.y > c.location.y - c.radius && mouse.y < c.location.y + c.radius) {
hover = true;
}
if (hover) {
$("canvas").hide();
$("#message").html("Sorry you lost. You finished with a score of " + score + "!");
}
}
}
setInterval(draw, 33);
var increase = function() {
if (mouse.x > 1 && mouse.y > 1 && !hover) {
score++;
redDots += 25;
$("#score").html("Score - " + score);
console.log(redDots);
}
if (mouse.x > canvas.width || mouse.y > canvas.height || mouse.x < 0 || mouse.y < 0) {
hover = true;
}
}
setInterval(increase, 1000);
});
All help is appreciated. Thanks in advance!
You just need a mouseout event listener, simple!
But first, you need to track the mouse on the mousemove, to prevent starting the game by clicking first. I have an example below.
canvas.addEventListener('mousemove', mousePos, false);
Use that instead of the mousedown event listener.
Second, to fix the problem of stopping the game upon mouseout.
Here is an example
canvas.addEventListener('mouseout', function() {
$("canvas").hide();
$("#message").html("Sorry you lost. You finished with a score of " + score + "!");
}, false);
What this does is the same thing as when your mouse touches a red dot, but it will display the message upon your mouse leaving the canvas. There you go!
Here is an example codepen of the working version: Avoid The Red Dots
My suggestion is to track whether the mouse is in the document or not, and use that in your if statement as well. This code will track whether the mouse is in the document (or use a selector for your game-screen element if it's not the full height and width of the document):
var mouseIn = false;
$(document).on('mouseenter mouseover', function(){
if(!mouseIn)mouseIn = true;
});
$(document).on('mouseleave', function(){
if(mouseIn)mouseIn = false;
});
Then just check if mouseIn evaluates to true to see if the user's cursor is on the game-screen. Here's a fiddle demonstrating the mouseIn change: https://jsfiddle.net/sk23cssc/
Add event listeners, instead of tracking mouse movement.
canvas.addEventListener('mouseout', mouseOutFunction, false);
This will run whatever function you provide for the second argument when the mouse leaves the screen.
If you want to start tracking score when the page loads, use the ready() function on the canvas
canvas.ready(pageLoadFunction);
This will run a function pageLoadFunction when canvas is finished loading

show hidden div and smoothly scroll to anchor point within hidden div

I have many hidden divs (within the normal site layout) which I make shown only one at a time and in all cases the screen scrolls to those specific divs. This code works nicely but I want it to open the hidden div and scroll to the anchor within that div.
I can't seem to ingrate something that does it all. In this case it will only arrive at the top of the hidden div.
var holder = "";
function toggleDiv(id) {
if (holder != "") {
document.getElementById(holder).style.display = 'none';
}
document.getElementById(id).style.display = 'block';
holder = id;
var startY = currentYPosition();
var stopY = elmYPosition(id);
var distance = stopY > startY ? stopY - startY : startY - stopY;
if (distance < 100) {
scrollTo(0, stopY);
return;
}
var speed = Math.round(distance / 100);
if (speed >= 10) speed = 10;
var step = Math.round(distance / 25);
var leapY = stopY > startY ? startY + step : startY - step;
var timer = 0;
if (stopY > startY) {
for (var i = startY; i < stopY; i += step) {
setTimeout("window.scrollTo(0, " + leapY + ")", timer * speed);
leapY += step;
if (leapY > stopY) leapY = stopY;
timer++;
}
return;
}
for (var i = startY; i > stopY; i -= step) {
setTimeout("window.scrollTo(0, " + leapY + ")", timer * speed);
leapY -= step;
if (leapY < stopY) leapY = stopY;
timer++;
}
return false;
}
I also have this to make the whole scroll thing work:
function currentYPosition() {
// Firefox, Chrome, Opera, Safari
if (self.pageYOffset) return self.pageYOffset;
// Internet Explorer 6 - standards mode
if (document.documentElement && document.documentElement.scrollTop)
return document.documentElement.scrollTop;
// Internet Explorer 6, 7 and 8
if (document.body.scrollTop) return document.body.scrollTop;
return 0;
}
function elmYPosition(id) {
var elm = document.getElementById(id);
var y = elm.offsetTop;
var node = elm;
while (node.offsetParent && node.offsetParent != document.body) {
node = node.offsetParent;
y += node.offsetTop;
}
return y;
}
So, what I would really like is to know if there is any command I can introduce in there to allow it to scroll smoothly/nicely to anchors instead of just jumping to them.
Thanks in advance.
You can animate the scroll:
$('html,body').animate({
scrollTop: $('#yourTarget').offset().top
}, 2000);
Also, you can't scroll to the hidden div, because display:none removes it from the DOM, when you should actually be using visibility:hidden, so you can still use the anchor.

how to play a video file when scrolled into view

So Im trying to activate videos when they scroll into the viewport and just calling their different IDs but its not working, admittedly I am very new to this (js/jquery) and am not 100% about whats going on so any help would be great.
Just to be clear Im trying to get each video to play separately whenever they are scrolled into view, I have the 1st video working but none of the other subsequent videos play when scrolled over.
I created this to help with seeing what Im trying to accomplish http://jsfiddle.net/8TpN5/
Update: Ok so this is how I want it to work http://jsfiddle.net/8TpN5/1/ but how could I get it to work and not repeat the code?
var videoId = document.getElementById("video","videoTwo");
var playVideo = videoId,
fraction = 0.9;
function checkScroll() {
var x = playVideo.offsetLeft,
y = playVideo.offsetTop,
w = playVideo.offsetWidth,
h = playVideo.offsetHeight,
r = x + w, //right
b = y + h, //bottom
visibleX,
visibleY,
visible;
if (window.pageXOffset >= r || window.pageYOffset >= b || window.pageXOffset + window.innerWidth < x || window.pageYOffset + window.innerHeight < y) {
return;
}
visibleX = Math.max(0, Math.min(w, window.pageXOffset + window.innerWidth - x, r - window.pageXOffset));
visibleY = Math.max(0, Math.min(h, window.pageYOffset + window.innerHeight - y, b - window.pageYOffset));
visible = visibleX * visibleY / (w * h);
if (visible > fraction) {
playVideo.play();
} else {
playVideo.pause();
}
}
checkScroll();
window.addEventListener('scroll', checkScroll, false);
window.addEventListener('resize', checkScroll, false);
This line:
var videoId = document.getElementById("video","videoTwo");
Should be:
var videoOne = document.getElementById("video"),
videoTwo = document.getElementById("videoTwo");
getElementById only takes one id as parameter and returns one object.
just change the getElementById to getElementsByTagName.
Hope this helps:
http://jsfiddle.net/jAsDJ/
var videos = document.getElementsByTagName("video"),
fraction = 0.8;
function checkScroll() {
for(var i = 0; i < videos.length; i++) {
var video = videos[i];
var x = video.offsetLeft, y = video.offsetTop, w = video.offsetWidth, h = video.offsetHeight, r = x + w, //right
b = y + h, //bottom
visibleX, visibleY, visible;
visibleX = Math.max(0, Math.min(w, window.pageXOffset + window.innerWidth - x, r - window.pageXOffset));
visibleY = Math.max(0, Math.min(h, window.pageYOffset + window.innerHeight - y, b - window.pageYOffset));
visible = visibleX * visibleY / (w * h);
if (visible > fraction) {
video.play();
} else {
video.pause();
}
}
}
window.addEventListener('scroll', checkScroll, false);
window.addEventListener('resize', checkScroll, false);

Move Depending on Mouse State

I need my users to be able to move an element away from the mouse pointer by holding the left button down, and the element should move closer when the button is up. So far, I have this:
var divName = 'follow'; // div to follow mouse
// (must be position:absolute)
var offX = 0; // X distance from mouse
var offY = 0; // Y distance from mouse
function mouseX(evt) {
if (!evt) evt = window.event;
if (evt.pageX) return evt.pageX;
else if (evt.clientX) return evt.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);
else return 0;
}
function mouseY(evt) {
if (!evt) evt = window.event;
if (evt.pageY) return evt.pageY;
else if (evt.clientY) return evt.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
else return 0;
}
function follow(evt) {
if (document.getElementById) {
var obj = document.getElementById(divName).style;
obj.visibility = 'visible';
obj.left = (parseInt(mouseX(evt)) + offX) + 'px';
obj.top = (parseInt(mouseY(evt)) + offY) + 'px';
}
}
document.onmousemove = follow;
function discharge() { //Move away
offX += 1;
offY += 1;
}
function pull() { //Come closer
if (offX > 0) {
offX -= 1;
}
if (offY > 0) {
offY -= 1;
}
}
document.onmousedown = discharge;
document.onmouseup = pull;
offX and offY are the distance the element is from the mouse. In addition, this is just one part of the script. offX and offY come into play in a different part, which works except for this push/pull.
EDIT: Updated to include whole file and here is a fiddle.
More info: My main goal was to have an image within a div follow the mouse and move closer/further depending on the mouse's state. If anyone has a different way to achieve this, it would be greatly appreciated as well.
What you want requires two offsets, those of the mouse and those of the element.
var offX = 100; // mouse X-axis
var offY = 50; // mouse Y-axis
var elemOffX = 950; // elem X-axis
var elemOffY = 600; // elem Y-axis
// Now get the distance from the elem to the mouse:
var diffX = offX - elemOffX; // get the diff X
var diffY = offY - elemOffY; // get the diff Y
// Depending on your interval you might want to change the factor,
// this will move it in steps of 10%
var newOffX = offX + (diffX * 0.1); // set this as new result for the element's X
var newOffY = offY + (diffY * 0.1); // set this as new result for the element's Y
Please note, I havent tested this for bugs, this is to show a principle. Might be that you need to change the newOff's + to a -
In you example you do this: offY-1, you need to change that to offY=offY-1 or offY-=1
Here's a complete example using JQuery:
var divName = 'follow'; // div to follow mouse
// (must be position:absolute)
var offX = 0; // X distance from mouse
var offY = 0; // Y distance from mouse
var mouseX;
var mouseY;
var mouseState = 0;
var _this = this;
function follow(evt) {
if(_this.mouseState === 1) {
discharge();
} else {
pull();
}
if (document.getElementById) {
var obj = document.getElementById(divName).style;
obj.visibility = 'visible';
obj.left = evt.pageX + _this.offX + 'px';
obj.top = evt.pageY + _this.offY + 'px';
}
}
document.onmousemove = follow;
function discharge() { //Move away
_this.offX += 1;
_this.offY += 1;
}
function pull() { //Come closer
if (_this.offX > 0) {
_this.offX -= 1;
}
if (_this.offY > 0) {
_this.offY -= 1;
}
}
$(document).mousedown(function(e){_this.mouseState = 1;});
$(document).mouseup(function(e){_this.mouseState = 0; });

Categories

Resources