Problem while trying to scroll window to an element position using intersectionObserver - javascript

I'm trying to make slide-show website using intersectionObserver. Basically, i grep elements and listen for intersection event, then i want to set window.srollTo to element's offsetTop. I have tried window.scrollTo(0, 10), elem.scrollIntoView(), window.scrollBy(), but nothing is working at all.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title></title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body,
html {
position: ablolute;
-ms-overflow-style: none;
display: block;
height: 100vh;
width: 100%;
}
body::-webkit-scrollbar {
width: 0 !important;
}
.page {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div class="page">one</div>
<div class="page">two</div>
<div class="page">three</div>
<div class="page">four</div>
<script>
const pages = document.querySelectorAll('.page');
const observer = new IntersectionObserver(
entries => {
entries.forEach(entry => {
if (entry.isIntersecting == true) {
console.log(entry.target.offsetTop);
entry.target.scrollIntoView(top);
}
});
},
{threshold: 0.01},
);
pages.forEach(page => {
observer.observe(page);
});
</script>
</body>
</html>

Firstly scrollIntoView takes a Boolean or an options Object. I don't know what top is supposed to be since it's not in your code, but it's not correct.
Your scroll event is firing constantly and overriding your scrollIntoView. In order to stop this you can set the container's overflow property so that it no longer allows scrolling, disabling the event, and then re-enable it with a timer just before calling scrollIntoView.
entries.forEach(entry => {
if (entry.isIntersecting == true) {
console.log(entry.target.offsetTop);
document.body.setAttribute('style','overflow:hidden;');
setTimeout(function(){
document.body.setAttribute('style','overflow:visible;');
entry.target.scrollIntoView(true);
}, 250);
}
Example:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title></title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body,
html {
position: absolute;
-ms-overflow-style: none;
display: block;
height: 100vh;
width: 100%;
}
body::-webkit-scrollbar {
width: 0 !important;
}
.page {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div class="page">one</div>
<div class="page">two</div>
<div class="page">three</div>
<div class="page">four</div>
<script>
const pages = document.querySelectorAll('.page');
const observer = new IntersectionObserver(
entries => {
entries.forEach(entry => {
if (entry.isIntersecting == true) {
console.log(entry.target.offsetTop);
document.body.setAttribute('style','overflow:hidden;');
setTimeout(function(){
document.body.setAttribute('style','overflow:visible;');
entry.target.scrollIntoView(true);
}, 250);
}
});
},
{threshold: 0.10},
);
pages.forEach(page => {
observer.observe(page);
});
</script>
</body>
</html>
Note There are likely better ways to do this without a timer - for instance a flag within a closure, etc, but this should give you an idea of what's causing the issue and how to get around it.

Related

How to Incrementally Update an Elements Scale by Pinching with Js

The below code ALMOST works and I think I'm close yet quite far away from getting it to work properly. The problem is, the way the handlePinch function is set up. What actually happens when the user pinches to zoom a bit, is the square starts to accelerate. The more the user pinches, the faster the square zooms.
How can this be implemented that each time the user pinches to zoom, it incrementally scales, i.e. picking up where it left off without exceeding the max scale?
I'm stuck on this for two days and there doesn't seem to be any formula to show how something like this works. Note, I know there are libraries for this, I want to know how this works with vanilla js
const box = document.querySelector('.box')
function updateCss(scale) {
box.style.transform = `scale(${scale})`
}
let lastScale
let currentScale
let isAlreadyScaled = false
const minScale = 1
const maxScale = 1.8
function handlePinch(e) {
e.preventDefault()
const isZooming = e.scale > 1
if (isZooming) {
if (!isAlreadyScaled) {
lastScale = Math.min(minScale * e.scale, maxScale)
isAlreadyScaled = true
} else {
lastScale = Math.min(minScale * (lastScale * e.scale), maxScale)
}
}
updateCss(lastScale)
}
box.addEventListener('touchstart', e => {
if (e.touches.length === 2) {
handlePinch(e)
}
})
box.addEventListener('touchmove', e => {
if (e.touches.length === 2) {
handlePinch(e)
}
})
* {
box-sizing: border-box;
}
body {
padding: 0;
margin: 0;
}
.wrapper {
height: 400px;
width: 100%;
top: 0;
left: 0;
position: relative;
margin: 24px;
}
.scale-container {
height: 100%;
width: 100%;
position: absolute;
background: #eee;
display: flex;
align-items: center;
justify-content: center;
}
.box {
height: 200px;
width: 200px;
background: pink;
position: absolute;
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Home</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
</head>
<body>
<div class="wrapper">
<div class="scale-container">
<div class="box"></div>
</div>
</div>
</body>
</html>

jquery draggable, making a div not to go outside of the other div frame

i need a draggable div not to go outside of second div frame, so far i managed to make a "collision" basically returning true or false if draggable div is inside the frame of other div. So the thing now is that i cant get this to work, i was trying to get it to a x = 90(example) when it hits the frame and few more examples , but i just can't get this to work. The draggable div doesn't want to go back to position.
Here is a JSFiddle: https://jsfiddle.net/kojaa/x80wL1mj/2/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="style.css">
<title>Catch a ball</title>
</head>
<body>
<div class="catcherMovableArea" id="catcherMovableArea">
<div id="catcher" class="catcher"></div>
</div>
<script src="script.js"></script>
</body>
</html>
.catcherMovableArea {
position: absolute;
border: 1px solid black;
width: 1900px;
top: 90%;
height: 50px;
}
.catcher {
position: absolute;
width: 250px;
height: 30px;
border-radius: 10px;
background-color: black;
top: 20%;
}
let catcher = $("#catcher");
$(document).mousemove(function(e) {
catcher.position({
my: "left-50% bottom+50%",
of: e,
collision: "fit"
});
let catcherOffset = $(catcher).offset();
let CxPos = catcherOffset.left;
let CyPos = catcherOffset.top;
let catcherYInMovableArea, catcherXInMovableArea = true;
while(!isCatcherYinMovableArea(CyPos)){
catcherYInMovableArea = false;
break;
}
while(!isCatcherXinMovableArea(CxPos)){
catcherXInMovableArea = false;
break;
}
});
function isCatcherYinMovableArea(ypos){
if(ypos < 849.5999755859375 || ypos > 870.5999755859375) {
return false;
} else {
return true;
}
}
function isCatcherXinMovableArea(xpos){
if(xpos < 8 || xpos > 1655 ) {
return false;
} else {
return true;
}
}
By default, the collision option will prevent the element from being placed outside of the window. You want to prevent it from moving outside of a specific element.
To do this, use the within option to select which element should be used for containment.
Example:
let draggable = $("#draggable");
$(document).mousemove(function(e) {
draggable.position({
my: "left-50% bottom+50%",
of: e,
collision: "fit",
within: "#container"
});
});
#container { width: 200px; height: 100px; border-style: solid }
#draggable { width: 50px; height: 50px; background-color: black }
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://code.jquery.com/ui/1.12.0-rc.1/jquery-ui.js"></script>
<div id="container">
<div id="draggable"></div>
</div>

Function on resize doesn't work

Hello I have problem with really easy script. It should change class if under 768 px of window width but it just doesn't work. I have no clue why. I dont want to use media queries in this in this case.
Here's code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>ez</title>
<style>
.aside {
float: left;
height: 1000px;
width: 250px;
background-color: grey;
}
.sidebar {
position: absolute;
top: 0;
left: -250px;
}
</style>
</head>
<body style="height: 2000px">
<aside class="aside" id="aside"></aside>
<main style="float: left; height: 1000px; width: 70%; background-color: black;"></main>
<script>
var elm = document.getElementById("aside");
function change() {
var w = window.innerWidth;
if(w<768) {
elm.className = "sidebar";
} else {
elm.className = "aside";
}
}
window.addEventListener("resize", change);
</script>
</body>
</html>
I started your script. For 768px and more there is class 'aside', for 767px and less class 'sidebar'. So where is the problem?
If you open page on width less than 768 your script won't be working correct. You have to add it to event onload too

Backwards animation not working properly in Game

I'm trying to make a simple Javascript game which consists in a square expanding, while the player have to hit "A" to make it smaller. The goal is to make the square disappear and not to let the square engulf the whole screen.
But I'm experiencing three issues:
- When I hit A, the square stops expanding and starts getting smaller, but it never stops. It should only work for a about a second and then expand again.
- The pause button (enter) doesn't always work the way it should. I feel like it waits for the animation stop, but I don't want it to work like this.
- The square doesn't expand from the center.
The HTML:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="styles/game.css"></link>
<script language="javascript" type="text/javascript" src="scripts/jquery-1.11.3.min.js"></script>
<script type="text/javascript" src="scripts/game.js"></script>
</head>
<body>
<section class="game">
<div id="game" style="position:absolute;"><img id="player" class="square"></img></div>
</section>
</body>
</html>
The Javascript:
//set update interval
setInterval(update, 10);
var isPlaying = false;
$(document).ready(function() {
});
function playerInput() {
$(document).keydown(function(event) {
if ( event.which == 65 ) {
if (isPlaying == true) {
$("#player").animate({height: '-=10', width: '-=10'}, 1);
}
} else if (event.which == 13) {
isPlaying = !isPlaying;
}
});
}
function update() {
playerInput();
if (isPlaying == true) {
$("#player").animate({height: '+=10', width: '+=10'}, 1);
}
}
The CSS:
body, html {
height: 1000px;
width: 1000px;
margin: auto;
background-color: black;
}
.game {
height: 800px;
width: 800px;
margin: auto;
margin-top: 10px;
background-color: black;
}
.square {
background-image: url("../images/square.png");
margin: 375px;
height: 30px;
width: 30px;
}

Javascript drag and drop on leave doesn't work correctly

I am trying to implement a drag and drop image upload similar functionality to imgur.com.
You drag an image from your desktop and a big overlay div with the word 'upload' appears as you drag over your document.
My problem is that when I drag over the actual word 'upload' inside an h1 tag the screen flickers. This is happening because I have an event for dragleave to remove the overlay div with the upload h1 tag however I don't know how to fix it.
You can see the problem in action here: JS Fiddle, just drag any image from your desktop to the document and hover over the word 'upload' you'll see what I'm talking about. Any help would be appreciated.
HTML:
<!DOCTYPE html>
<html>
<head>
<title>Drag and Drop</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
</head>
<body>
<div id="upload-global-drop-overlay" style="display: none;"><h1>upload</h1></div>
</body>
</html>​
Javascript code:
$(document).on('dragover', function () {
$('#upload-global-drop-overlay').css({'display': 'block'});
});
$('#upload-global-drop-overlay').on('dragleave', function () {
$('#upload-global-drop-overlay').css({'display': 'none'});
});
$(document).on('drop', function (e) {
$('#upload-global-drop-overlay').css({'display': 'none'});
e.preventDefault();
});
​
Hey hopefully you found an answer to this, if not here is a little example that looks like imgur in my oppinion, using your code.
jsFiddle: http://jsfiddle.net/JUBwS/74/
HTML:
<!DOCTYPE html>
<html>
<head>
<title>Drag and Drop</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
</head>
<body>
<div id="upload-global-drop-overlay" style="display: none;"><h1>upload</h1></div>
</body>
</html>​
CSS:
#upload-global-drop-overlay {
background: none repeat scroll 0 0 #424242;
height: 100%;
width: 100%;
position: fixed;
top: 0;
left: 0;
opacity: .8;
filter: alpha(opacity=80);
-moz-opacity: .8;
z-index: 10001;
display: none;
}
#upload-global-drop-overlay h1 {
font-size: 72pt;
display: block;
position: absolute;
line-height: 50px;
top: 50%;
left: 50%;
margin: -82px 0 0 -180px;
text-shadow: 3px 3px 4px black;
color: white;
z-index: -1;
}​
Javascript:
var isDragging = null;
$(document).on('dragover', function () {
if(isDragging==null)
doDrag();
isDragging = true;
});
$(document).on('drop', function (e) {
e.preventDefault();
isDragging = false;
});
$(document).on('dragleave', function (e) {
isDragging = false;
});
var timerId=0;
function doDrag()
{
timerId = setInterval(function()
{
if(isDragging)
$('#upload-global-drop-overlay').fadeIn(500);
else
{
$('#upload-global-drop-overlay').fadeOut(500);
isDragging = null;
clearInterval(timerId);
}
},200);
}​
This sample uses timers, but it is active only when something is being dragged into the form. I am certainly going to use this in the future.
I actually found another solution, I think it's a bit simpler because it doesn't use setInterval. And I've implemented the actual drag and drop functionality for anyone interested.
The whole working example with drag and drop functionality is available below.
jsFiddle - Demo: http://jsfiddle.net/6SV9P/1/
HTML:
<!DOCTYPE html>
<html>
<head>
<title>Drag and Drop</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
</head>
<body>
<div id="upload-global-drop-overlay" style="display: none;"><h1>upload</h1</div>
<div id="image"></div>
</body>
</html>​
CSS:
#upload-global-drop-overlay {
background: none repeat scroll 0 0 #424242;
height: 100%;
width: 100%;
position: fixed;
top: 0;
left: 0;
opacity: .8;
filter: alpha(opacity=80);
-moz-opacity: .8;
z-index: 10001;
display: none;
}
#upload-global-drop-overlay h1 {
font-size: 72pt;
display: block;
position: absolute;
line-height: 50px;
top: 50%;
left: 50%;
margin: -82px 0 0 -180px;
text-shadow: 3px 3px 4px black;
color: white;
z-index: -1;
}​
JS:
var dragDropFromDesktop = (function ($) {
$(document).on('dragenter', function () {
$('#upload-global-drop-overlay').fadeIn(200)
});
$('#upload-global-drop-overlay').on('dragleave', function (e) {
if (e.originalEvent.pageX < 10 || e.originalEvent.pageY < 10 || $(window).width() - e.originalEvent.pageX < 10 || $(window).height - e.originalEvent.pageY < 10) {
$("#upload-global-drop-overlay").fadeOut(200);
}
});
$('#upload-global-drop-overlay').on('dragover', function (e) {
e.stopPropagation();
e.preventDefault();
});
// Handle dropped image file - only Firefox and Google Chrome
$('#upload-global-drop-overlay').on('drop', function (e) {
$('#upload-global-drop-overlay').fadeOut(200);
var files = e.originalEvent.dataTransfer.files;
if (files === undefined) {
alert('Your browser does not support file Drag and Drop!')
} else {
var file = files[0];
if (typeof FileReader !== "undefined" && file.type.indexOf("image") != -1) {
var reader = new FileReader();
reader.onload = function (evt) {
var img = new Image();
img.src = evt.target.result;
$('#image').html('<img src="' + img.src + '">');
};
reader.readAsDataURL(file);
}
}
e.preventDefault();
e.stopPropagation();
});
})(jQuery);​

Categories