Drag and drop that works with touch and mouse? - javascript

I followed this guide and I tried implementing the code myself, but when I run it I get a "move is not defined" error. Any suggestions on what I did wrong? Tried moving the script reference around or not including the event listeners in the html tag which would constrain the movement to only inside the container, but nothing seems to change? Any suggestions? Thanks!
let moving = null;
function pickup(event) {
moving = event.target;
moving.style.height = moving.clientHeight;
moving.style.width = moving.clientWidth;
moving.style.position = 'fixed';
moving.style.zIndex = '-10';
}
function move(event) {
if (moving) {
if (event.clientX) {
// mousemove
moving.style.left = event.clientX - moving.clientWidth/2;
moving.style.top = event.clientY - moving.clientHeight/2;
} else {
// touchmove - assuming a single touchpoint
moving.style.left = event.changedTouches[0].clientX - moving.clientWidth/2;
moving.style.top = event.changedTouches[0].clientY - moving.clientHeight/2;
}
}
}
function drop(event) {
if (moving) {
if (event.currentTarget.tagName !== 'HTML') {
let target = null;
if (event.clientX) {
target = document.elementFromPoint(event.clientX, event.clientY);
} else {
target = document.elementFromPoint(event.changedTouches[0].clientX, event.changedTouches[0].clientY);
}
target.appendChild(moving);
}
// reset our element
moving.style.left = '';
moving.style.top = '';
moving.style.height = '';
moving.style.width = '';
moving.style.position = '';
moving.style.zIndex = '';
moving = null;
}
}
* {
box-sizing: border-box;
}
#container {
display: flex;
}
#container > div {
border: 1px solid gray;
padding: 1em;
height: 10em;
width: 50%;
}
#movable-element {
border: 1px solid green;
background-color: #00ff0033;
height: 100%;
width: 100%;
}
<html onmouseup="drop(event)" ontouchend="drop(event)" onmousemove="move(event)" ontouchmove="move(event)">
<head>
<title>Drag and Drop</title>
<script src="script.js"></script>
<link rel="stylesheet" href="style.css">
<body>
<div id="container">
<div id="left-parent" onmouseup="drop(event)" ontouchend="drop(event)">
<div id="movable-element" onmousedown="pickup(event)" ontouchstart="pickup(event)"></div>
</div>
<div id="right-parent" onmouseup="drop(event)" ontouchend="drop(event)"></div>
</div>
</body>

The problem with the "move is not defined" is because you're setting the move event listener on the HTML tag, which is before you defined the "move" function.
The solution is to move the event listeners to the body tag, which is after the move function is defined.
There are other issues with this code, but that addresses the one issue in your question. If you need further help with the other issues please post a new question.
let moving = null;
function pickup(event) {
moving = event.target;
moving.style.height = moving.clientHeight;
moving.style.width = moving.clientWidth;
moving.style.position = 'fixed';
moving.style.zIndex = '-10';
}
function move(event) {
if (moving) {
if (event.clientX) {
// mousemove
moving.style.left = event.clientX - moving.clientWidth/2;
moving.style.top = event.clientY - moving.clientHeight/2;
} else {
// touchmove - assuming a single touchpoint
moving.style.left = event.changedTouches[0].clientX - moving.clientWidth/2;
moving.style.top = event.changedTouches[0].clientY - moving.clientHeight/2;
}
}
}
function drop(event) {
if (moving) {
if (event.currentTarget.tagName !== 'HTML') {
let target = null;
if (event.clientX) {
target = document.elementFromPoint(event.clientX, event.clientY);
} else {
target = document.elementFromPoint(event.changedTouches[0].clientX, event.changedTouches[0].clientY);
}
target.appendChild(moving);
}
// reset our element
moving.style.left = '';
moving.style.top = '';
moving.style.height = '';
moving.style.width = '';
moving.style.position = '';
moving.style.zIndex = '';
moving = null;
}
}
* {
box-sizing: border-box;
}
#container {
display: flex;
}
#container > div {
border: 1px solid gray;
padding: 1em;
height: 10em;
width: 50%;
}
#movable-element {
border: 1px solid green;
background-color: #00ff0033;
height: 100%;
width: 100%;
}
<html>
<head>
<title>Drag and Drop</title>
<script src="script.js"></script>
<link rel="stylesheet" href="style.css">
<body onmouseup="drop(event)" ontouchend="drop(event)" onmousemove="move(event)" ontouchmove="move(event)">
<div id="container">
<div id="left-parent" onmouseup="drop(event)" ontouchend="drop(event)">
<div id="movable-element" onmousedown="pickup(event)" ontouchstart="pickup(event)"></div>
</div>
<div id="right-parent" onmouseup="drop(event)" ontouchend="drop(event)"></div>
</div>
</body>

Related

how can I let 3 div elements being resizable

what I want to see the result is 2 set of split view screen (or more), one is vertical, one is horizontal, but in the same javascript file. If it's possible to do in a single JavaScript file will be good
I tried to use this one to make it but it seems like not how to make that.
Here's the code I'm trying to make two div elements and its vertical
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>my app</title>
<style>
.container {
width: 202px;
height: 406px;
border: 1px solid black;
display: flex;
flex-direction: column;
}
.top {
width: 200px;
height: 200px;
border: 1px solid red;
min-height: 100px;
}
.resizer {
width: 202px;
height: 2px;
background-color: green;
}
.resizer:hover {
cursor: ns-resize;
}
.bottom {
width: 200px;
height: 200px;
border: 1px solid blue;
flex: 1 1 0%;
min-height: 100px;
}
</style>
</head>
<body>
<div class="container">
<div class="top" id="top">
something here
</div>
<div class="resizer" id="resizer"></div>
<div class="bottom" id="bottom">
something too
</div>
</div>
<script>
const resizer = document.getElementById('resizer');
const topSection = document.getElementById('top');
const bottomSection = document.getElementById('bottom');
let x = 0;
let y = 0;
let topSectionHeight = 0;
const mouseDownHandler = function (e) {
x = e.clientX;
y = e.clientY;
topSectionHeight = topSection.getBoundingClientRect().height;
document.addEventListener('mousemove', mouseMoveHandler);
document.addEventListener('mouseup', mouseUpHandler);
}
resizer.addEventListener('mousedown', mouseDownHandler);
const mouseMoveHandler = function (e) {
const dx = e.clientX - x;
const dy = e.clientY - y;
const newtopSectionHeight = ((topSectionHeight + dy) * 100) / resizer.parentNode.getBoundingClientRect().height;
topSection.style.height = `${newtopSectionHeight}%`;
resizer.style.cursor = 'ns-resize';
document.body.style.cursor = 'ns-resize';
topSection.style.userSelect = 'none';
topSection.style.pointerEvents = 'none';
bottomSection.style.userSelect = 'none';
bottomSection.style.pointerEvents = 'none';
}
const mouseUpHandler = function () {
resizer.style.removeProperty('cursor');
document.body.style.removeProperty('cursor');
actionBasic.style.removeProperty('user-select');
actionBasic.style.removeProperty('pointer-events');
bottomSection.style.removeProperty('user-select');
bottomSection.style.removeProperty('pointer-events');
document.removeEventListener('mousemove', mouseMoveHandler);
document.removeEventListener('mouseup', mouseUpHandler);
}
</script>
</body>
</html>
thank you for reading so far, please help me if you're able to! If any information is needed, please tell me below and I'll provide it as soon as possible.

How to hide a custom context menu when over a button or element

I am looking for a simple way to hide the custom context menu unless over a button or element. Here is a simple example I coded up containing a custom context menu and a button I wish to have it attached to. I am thinking maybe there could be an event listener that looks out for an on hover over the element, or maybe a function that toggles it on or off when needed? Also i was wondering if the button or element wasn't defined with a class or ID is there still a way to know when you are over it maybe via coordinates (Not necessary just curious if possible)? The idea is there will be multiple elements that will require the context menu but the general space around the elements in the body should not show the custom menu.
function view() {
const contextMenu = document.getElementById('context-menu');
const scope = document.querySelector("body");
//body
var listLength = contextMenu.children.length;
for (i = 0; i < listLength; i++)
contextMenu.removeChild(contextMenu.children[0]);
contextMenuadd(contextMenu, "line 1 of context menu", 1);
contextMenuadd(contextMenu, "line 2 of context menu", 2);
contextMenuadd(contextMenu, "line 3 of context menu", 3);
contextMenuadd(contextMenu, "line 4 of context menu", 4);
scope.addEventListener("contextmenu", (event) => {
event.preventDefault();
const {
clientX: mouseX,
clientY: mouseY
} = event;
contextMenu.style.top = `${mouseY}px`;
contextMenu.style.left = `${mouseX}px`;
contextMenu.classList.add('visible');
contextMenu.style.display = 'block';
contextMenu.style.zIndex = 20000;
contextMenu.style.position = 'fixed';
contextMenu.style.width = "360px";
contextMenu.style.borderRadius = "5px";
});
scope.addEventListener("click", (e) => {
if (e.target.offsetParent != contextMenu) {
contextMenu.style.display = 'none';
}
});
};
document.addEventListener('DOMContentLoaded', view);
function contextMenuadd(contextMenu, menustring, count) {
var action = function(e) {
//menuLink;
let currentRow = $(event.target)[0].parentElement;
var index = parseInt(currentRow.row);
var value = currentRow.textContent;
en(href, '_self');
};
var menuitem = document.createElement('LI');
menuitem.addEventListener('click', action);
menuitem.classList.add("hotspot__item");
menuitem.innerHTML = '' + menustring + '';
menuitem.row = count;
contextMenu.appendChild(menuitem);
};
document.addEventListener('click', function(e) {
let inside = (e.target.closest('#container'));
if (!inside) {
let contextMenu = document.getElementById('contextMenuId');
contextMenu.setAttribute('style', 'display:none');
}
});
#context-menu {
position: fixed;
z-index: 10000;
width: 180px;
background: #ffaaaa;
border-radius: 5px;
display: none;
}
#context-menu.item {
padding: 2px 4px;
font-size: 12px;
color: #eee;
cursor: pointer;
border-radius: inherit;
}
<body id="allofit">
<header>
<h2>Context Menu Example</h2>
</header>
<!-- <gm:figure-group> -->
<div id='sdi_canvas1' style="width:400px; height:400px">
<button id="container"> this is data in my DIV</button>
</div>
<div id="context-menu" class="context-menu"
oncontextmenu="ShowMenu('contextMenu',event)" style="display:none">
<div class="item">Option 1</div>
<div class="item">Option 2</div>
</div>
</body>
Here's a fiddle for reference JSFiddle
You can add a class to all the elements that will show the custom
context menu.
And oncontextmenu, you check if the element contains the class then toggle the context menu accordingly.
Try this
document.addEventListener('DOMContentLoaded', () => {
const scope = document.querySelector("body");
const contextMenu = document.getElementById('context-menu');
scope.addEventListener("contextmenu", (event) => {
event.preventDefault();
if( event.target.classList.contains('has-content-menu') ||
event.target.closest('.has-content-menu') !== null
){
contextMenu.style.top = event.clientY + 'px';
contextMenu.style.left = event.clientX + 'px';
contextMenu.style.display = 'block';
}else{
contextMenu.style.display = 'none';
}
});
scope.addEventListener("click", (event) => {
contextMenu.style.display = 'none';
});
});
*, ::after, ::before {
box-sizing: border-box;
}
body, html {
height: 100%;
}
#context-menu {
position: fixed;
z-index: 10000;
width: 180px;
background: #ffaaaa;
border-radius: 5px;
display: none;
z-index: 20000;
}
#context-menu.item {
padding: 2px 4px;
font-size: 12px;
color: #eee;
cursor: pointer;
border-radius: inherit;
}
<button class="has-content-menu"> this is data in my DIV</button>
<div id="context-menu">
<div class="item">Option 1</div>
<div class="item">Option 2</div>
</div>
Have you tried using a 'mouseover' and 'mouseout' events?
Let me know if this what you looking for:
const menu = document.querySelector('.menu')
const btn = document.getElementById('btn');
btn.addEventListener('mouseover', () => {
menu.style.display = "block";
});
btn.addEventListener('mouseout', () => {
menu.style.display = "none";
})
.menu {
display: none;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<button id="btn">Hover me</button>
<ul class="menu">
<li>Test 1</li>
<li>Test 1</li>
</ul>
</body>
</html>

Javascript: is it possible to determine how much user scrolls after reaching the end of a page?

On mobile, it's a common UI pattern to have a scrollable element inside a draggable element. When you reach the end of the scrollable element, you start dragging the outer element. E.g. in this GIF (https://media.giphy.com/media/9MJgBkoZfqA7jRdQop/giphy.gif), after scrolling to the top, if you continuing scrolling, it'll drag the subreddits menu.
I want to implement a similar pattern using JS/CSS. To do this, I need to detect if users continue scrolling after reaching the end. Is this possible? If so, is it possible to determine how much they scroll after reaching the end?
window.onscroll = function(element) {
if ((window.innerHeight + window.pageYOffset) >= document.body.offsetHeight) {
alert("you're at the bottom of the page");
}
};
Using element parameter to know the current exact x y where mouse is now at to calculate more and some how much was scrolled
Javascript: How to detect if browser window is scrolled to bottom?
If You need to keep track of the user activity after the bottom (or the top) of the page has been reached, beside the scroll event, You need to track the the wheel event. Moreover, on mobile, You need to track also touchstart and touchmove events.
Not all these events are normalized across browsers, so I did my own normalization function, which is more or less something like this:
var compulsivity = Math.log2(Math.max(scrollAmount, 0.01) * wheelAmount);
Below is a complete playground. You can test it in Chrome using the Mobile View of the Developer Tools, or in other browsers using the TouchEmulator.
function Tracker(page) {
this.page = page;
this.moveUp = 0;
this.moveDown = 0;
this.startTouches = {};
this.moveTouches = {};
this.lastScrollY = 0;
this.monitor = {};
this.startThreshold = 160;
this.moveThreshold = 10;
this.iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
this.pullToRefresh = window.chrome || navigator.userAgent.match('CriOS');
this.amplitude = 16 / Math.log(2);
this.page.ownerDocument.addEventListener( 'onwheel' in document ? 'wheel' : 'onmousewheel' in document ? 'mousewheel' : 'DOMMouseScroll', this, { passive: true } );
/* The basic scroll event cannot be canceled, so it does not need to be set passive.*/
this.page.ownerDocument.addEventListener('scroll', this);
this.page.addEventListener('touchstart', this, { passive: true });
/* Maybe we need to cancel pullToRefresh */
this.page.addEventListener('touchmove', this, { passive: false });
return this;
}
Tracker.prototype.handleEvent = function (e) { /* handleEvent is built-in */
var winHeight = (this.iOS ? document.documentElement.clientHeight : window.innerHeight) | 0,
currScrollY = window.pageYOffset | 0,
amountScrollY = (this.lastScrollY - currScrollY) | 0,
elHeight = this.page.offsetHeight | 0,
elTop = -currScrollY, elBottom = winHeight - elHeight + currScrollY,
isTop = elTop >= 0, isBottom = elBottom >= 0;
switch (e.type) {
case 'wheel':
case 'onmousewheel':
case 'mousewheel':
case 'DOMMouseScroll':
var wheelDelta = e.wheelDelta ? e.wheelDelta : e.deltaY ? -e.deltaY : -e.detail,
wheelDir = (wheelDelta > 0) - (wheelDelta < 0),
wheelUp = wheelDir < 0, wheelDown = wheelDir > 0,
wheelAmount = 100 * wheelDir;
if (isTop && wheelDown) {
this.moveUp++;
this.moveDown = 0;
} else if (isBottom && wheelUp) {
this.moveUp = 0;
this.moveDown++;
} else {
this.moveUp = 0;
this.moveDown = 0;
}
var compulsivity = this.amplitude * Math.log(Math.max(this.moveUp, this.moveDown, 0.01) * wheelAmount* wheelDir);
this.monitor[e.type].track(wheelAmount, compulsivity);
break;
case 'scroll':
/* end of scroll event for iOS, start/end of scroll event for other browsers */
this.lastScrollY = currScrollY;
this.monitor[e.type].track(amountScrollY, 0);
break;
case 'touchstart':
var touches = [].slice.call(e.touches), i = touches.length;
while (i--) {
var touch = touches[i], id = touch.identifier;
this.startTouches[id] = touch;
this.moveTouches[id] = touch;
}
break;
case 'touchmove':
var touches = [].slice.call(e.touches), i = touches.length,
currTouches = {},
swipeUp = false, swipeDown = false,
currMoveY = 0, totalMoveY = 0;
while (i--) {
var touch = touches[i], id = touch.identifier;
currTouches[id] = touch;
if (id in this.moveTouches) {
currMoveY = this.moveTouches[id].screenY - touch.screenY;
}
if (id in this.startTouches) {
totalMoveY = this.startTouches[id].screenY - touch.screenY;
}
swipeUp = currMoveY > 0 || totalMoveY > 0;
swipeDown = currMoveY < 0 || totalMoveY < 0;
if (this.pullToRefresh && isTop && swipeDown && e.cancelable) {
e.preventDefault();
console.log('Reload prevented');
}
}
this.moveTouches = currTouches;
var moveDir = (totalMoveY > 0) - (totalMoveY < 0),
longSwipe = moveDir * totalMoveY > this.startThreshold,
shortSwipe = moveDir * totalMoveY > this.moveThreshold,
realSwipe = longSwipe || shortSwipe;
if (isTop && swipeDown) {
if (realSwipe) this.moveUp++;
this.moveDown = 0;
} else if (isBottom && swipeUp) {
this.moveUp = 0;
if (realSwipe) this.moveDown++;
} else {
this.moveUp = 0;
this.moveDown = 0;
}
var compulsivity = this.amplitude * Math.log(Math.max(this.moveUp, this.moveDown, 0.01) * moveDir * totalMoveY);
this.monitor[e.type].track(currMoveY, compulsivity);
break;
}
};
function Monitor(events) {
this.ctx = null;
this.cont = null;
this.events = events;
this.values = [];
this.average = 0;
this.lastDrawTime = 0;
this.inertiaDuration = 200;
return this;
}
Monitor.prototype.showOn = function (container) {
var cv = document.createElement('canvas');
this.ctx = cv.getContext('2d');
this.cont = document.getElementById(container);
cv.width = this.cont.offsetWidth;
cv.height = this.cont.offsetHeight;
cv.style.top = 0;
cv.style.left = 0;
cv.style.zIndex = -1;
cv.style.position = 'absolute';
cv.style.backgroundColor = '#000';
this.cont.appendChild(cv);
var self = this;
window.addEventListener('resize', function () {
var cv = self.ctx.canvas, cont = self.cont;
cv.width = cont.offsetWidth;
cv.height = cont.offsetHeight;
});
return this;
};
Monitor.prototype.track = function (value, average) {
this.average = average;
if (this.values.push(value) > this.ctx.canvas.width) this.values.shift();
if (value) this.lastDrawTime = new Date().getTime();
};
Monitor.prototype.draw = function () {
if (this.ctx) {
var cv = this.ctx.canvas, w = cv.width, h = cv.height;
var i = this.values.length, x = w | 0, y = (0.5 * h) | 0;
cv.style.backgroundColor = 'rgb(' + this.average + ', 0, 0)';
this.ctx.clearRect(0, 0, w, h);
this.ctx.strokeStyle = '#00ffff';
this.ctx.lineWidth = 1;
this.ctx.beginPath();
while (i--) {
x -= 4;
if (x < 0) break;
this.ctx.moveTo(x, y);
this.ctx.lineTo(x + 1, y);
this.ctx.lineTo(x + 1, y - this.values[i]);
}
this.ctx.stroke();
var elapsed = new Date().getTime() - this.lastDrawTime;
/* cool down */
this.average = this.average > 0 ? (this.average * 0.9) | 0 : 0;
if (elapsed > this.inertiaDuration) {
this.track(0, this.average);
}
}
var self = this;
setTimeout(function () {
self.draw();
}, 100);
};
Monitor.prototype.connectTo = function (tracker) {
var events = this.events.split(' '), i = events.length;
while (i--) {
tracker.monitor[events[i]] = this;
}
this.draw();
return this;
};
function loadSomeData(target) {
$.ajax({
url: 'https://jsonplaceholder.typicode.com/users',
method: 'GET',
crossDomain: true,
dataType: 'json',
success: function (users) {
var html = '', $ul = $(target).find('ul');
$.each(users, function (i, user) {
var item = '<li><a class="ui-alt-icon ui-nodisc-icon">';
item += '<h2>' + user.name + '</h2>';
item += '<p><strong>' + user.company.name + '</strong></p>';
item += '<p>' + user.address.zipcode + ', ' + user.address.city + '</p>';
item += '<p>' + user.phone + '</p>';
item += '<p>' + user.email + '</p>';
item += '<p class="ui-body-inherit ui-li-aside ui-li-count"><strong>' + user.id + '</strong></p>';
item += '</a></li>';
html += item;
});
$ul.append(html).listview('refresh');
},
});
}
$(document)
.on('pagecreate', '#page-list', function (e) {
$("[data-role='header'], [data-role='footer']").toolbar({ theme: 'a', position: 'fixed', tapToggle: false });
loadSomeData(e.target);
})
.on('pageshow', '#page-list', function (e, ui) {
var tracker = $.data(this, 'mobile-page', new Tracker(this));
new Monitor('touchstart touchmove').connectTo(tracker).showOn('header');
new Monitor('scroll wheel mousewheel DOMMouseScroll').connectTo(tracker).showOn('footer');
});
.ui-page {
touch-action: none;
}
h1, h2, h3, h4, h5, h6, p {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
/* JQM no frills */
.ui-btn,
.ui-title,
.ui-btn:hover,
.ui-btn:focus,
.ui-btn:active,
.ui-btn:visited {
text-shadow: none !important;
}
* {
-webkit-box-shadow: none !important;
-moz-box-shadow: none !important;
box-shadow: none !important;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Compulsivity</title>
<meta name="description" content="Compulsivity" />
<meta name="HandheldFriendly" content="True" />
<meta name="MobileOptimized" content="320" />
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, width=device-width, minimal-ui shrink-to-fit=no" />
<meta http-equiv="cleartype" content="on" />
<!-- Add to homescreen for Chrome on Android -->
<meta name="mobile-web-app-capable" content="yes" />
<!-- For iOS web apps. Delete if not needed. -->
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="apple-mobile-web-app-title" content="Compulsivity" />
<link rel="stylesheet" href="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css" />
<!--
<script type="application/javascript" src="lib/touch-emulator.js"></script>
<script> TouchEmulator(); </script>
-->
<script type="application/javascript" src="https://cdn.jsdelivr.net/npm/jquery#2.2.4/dist/jquery.min.js"></script>
<script type="application/javascript" src="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>
</head>
<body>
<div id="header" data-role="header"><h4 style="color: #fff">Compulsivity</h4></div>
<div id="page-list" data-role="page">
<div data-role="content" role="main">
<ul data-role="listview" data-filter="true" data-inset="true"></ul>
</div>
</div>
<div id="footer" data-role="footer"><h4 style="color: #fff">Scroll</h4></div>
</body>
</html>
Among others, You need to be aware also of the pull-to-refresh and inertia (or momentum) of the smooth scroll behaviors.
Please, try to scroll or to swipe and look how the events are tracked: either the top bar or bottom bar will change color to display the user activity after reaching the bottom or the top respectively of the page.
JavaScript:
// get the button
var theBtn = document.getElementById('theBtn');
// get the box
var theBox = document.getElementById('theBox');
// add event to the button on click show/hide(toggle) the box
theBtn.addEventListener('click', () => {
theBox.classList.toggle('active');
});
// when scrolling on the box
theBox.onscroll = function(){
// get the top of the div
var theBoxTop = theBox.scrollTop;
if(theBoxTop <= 0){
// when it reaches 0 or less, hide the box. It'll toggle the class, since it's "show" will "hide"
theBox.classList.toggle('active');
}
};
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-size: 10px;
font-family: 'Arial', sans-serif;
height: 1500px;
}
html {
scroll-behavior: smooth;
}
ul {
list-style-type: none;
}
#theBox ul li {
border: 1px solid;
height: 100px;
}
#navbar-bottom {
height: 100px;
width: 100%;
background: rgb(90, 111, 143);
position: fixed;
bottom: 0;
left: 0;
right: 0;
box-shadow: 0 0 2px 2px rgba(90, 111, 143, 0.562);
display: flex;
justify-content: space-around;
align-items: center;
}
#theBox {
background-color: red;
height: 350px;
width: 100%;
position: fixed;
bottom: 0;
transform: translateY(100%);
transition: all 0.3s;
overflow-y: scroll;
}
#theBox.active{
transform: translateY(0);
}
.myBtns {
width: 50px;
height: 50px;
border-radius: 50%;
border: none;
position: relative;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
cursor: pointer;
}
.myBtns span {
height: 3px;
width: 30px;
background-color: black;
margin: 3px 0;
}
<main role="main">
<div id="theBox">
<ul>
<li><p>Text</p></li>
<li><p>Text</p></li>
<li><p>Text</p></li>
<li><p>Text</p></li>
<li><p>Text</p></li>
<li><p>Text</p></li>
<li><p>Text</p></li>
<li><p>Text</p></li>
<li><p>Text</p></li>
</ul>
</div>
<div id="navbar-bottom">
<button class="myBtns"></button>
<button class="myBtns" id="theBtn">
<span></span>
<span></span>
<span></span>
</button>
<button class="myBtns"></button>
</div>
</main>
jQuery:
// add event to the button on click show/hide(toggle) the box
$('#theBtn').click(function(){
$('#theBox').toggleClass('active');
});
// when scrolling on the box
$('#theBox').scroll(function () {
// get the top of the div
var theBoxTop = $('#theBox').scrollTop();
// when it reaches 0 or less, hide the box. It'll toggle the class, since it's "show" will "hide"
if(theBoxTop <= 0){
$('#theBox').toggleClass('active');
}
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-size: 10px;
font-family: 'Arial', sans-serif;
height: 1500px;
}
html {
scroll-behavior: smooth;
}
ul {
list-style-type: none;
}
#theBox ul li {
border: 1px solid;
height: 100px;
}
#navbar-bottom {
height: 100px;
width: 100%;
background: rgb(90, 111, 143);
position: fixed;
bottom: 0;
left: 0;
right: 0;
box-shadow: 0 0 2px 2px rgba(90, 111, 143, 0.562);
display: flex;
justify-content: space-around;
align-items: center;
}
#theBox {
background-color: red;
height: 350px;
width: 100%;
position: fixed;
bottom: 0;
transform: translateY(100%);
transition: all 0.3s;
overflow-y: scroll;
}
#theBox.active{
transform: translateY(0);
}
.myBtns {
width: 50px;
height: 50px;
border-radius: 50%;
border: none;
position: relative;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
cursor: pointer;
}
.myBtns span {
height: 3px;
width: 30px;
background-color: black;
margin: 3px 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<main role="main">
<div id="theBox">
<ul>
<li><p>Text</p></li>
<li><p>Text</p></li>
<li><p>Text</p></li>
<li><p>Text</p></li>
<li><p>Text</p></li>
<li><p>Text</p></li>
<li><p>Text</p></li>
<li><p>Text</p></li>
<li><p>Text</p></li>
</ul>
</div>
<div id="navbar-bottom">
<button class="myBtns"></button>
<button class="myBtns" id="theBtn">
<span></span>
<span></span>
<span></span>
</button>
<button class="myBtns"></button>
</div>
</main>
window.onscroll = function(ev) {
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
alert("you are at the bottom of the page");
}
};
Link to demo: http://jsfiddle.net/5xpoe4yg/
There are two solutions for this. One is for touch devices and second for devices using mouse.
Using Wheel event
If target is a mouse device, then we will use following method:
document.onwheel = event => ScrollAction(event);
For more info on wheel event, please visit this link.
Touch Devices
If target is a touch device then following method will be useful:
document.ontouchcancel = event => TouchInterrupt(event);
document.ontouchend = event => FingerRemoved(event);
document.ontouchmove = event => FingerDragged(event);
document.ontouchstart = event => FingerPlaced(event);
For more info on touch events, please visit this link.
I think your problem fully is solved by this solution.
Your specific question is solveable by listening to the wheel event, although the result is not terribly precise. The wheel event often fires before the scroll event so this example will sometimes log negative scroll value on the first scroll up from the bottom of the page:
const content = document.querySelector('.content');
for (let i = 0; i < 50; i++) {
const p = document.createElement('p');
p.textContent = 'Content';
content.append(p);
};
content.addEventListener('wheel', e => {
const atBottom = content.scrollHeight - content.scrollTop === content.clientHeight;
if (atBottom) console.log(e.deltaY);
});
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
height: 100vh;
width: 100%;
}
.content {
overflow-y: scroll;
height: 100%;
}
<div class="content"></div>
As others have suggested, a better approach for your use case might instead be to have an overlay which you can trigger on click/touch and then scroll into view. One issue you might run into is that deeply nested scroll on web browsers can get real ugly real fast, without resorting to pure JS solutions which also have their own performance issues.
This is a popup that, when clicked on, opens and enables you to scroll. When it gets to the top of the page, it's header sticks.
var navbar = document.querySelector('.navbar'),
navheader = document.querySelector('.navheader');
// Toggle navbar
navheader.addEventListener('click', e => {
navbar.classList.toggle('open');
if (!navbar.classList.contains('open')) {
navbar.style.overflow = 'hidden';
document.body.style.overflow = '';
navbar.scrollTop = 0;
stickTop = false;
navbar.classList.remove('sticky');
navbar.style.top = '';
navbar.style.transition = '.2s';
setTimeout(() => {
navbar.style.transition = '';
}, 200);
}
else {
navbar.style.overflow = 'overlay';
navbar.style.transition = '.2s';
setTimeout(() => {
navbar.style.transition = '';
}, 200);
}
})
var prevtop = 0;
var stickTop = false;
// Add scroll listener
navbar.addEventListener('scroll', e => {
// If navbar is open
if (navbar.classList.contains('open')) {
if (!stickTop) {
navbar.style.top = navbar.getBoundingClientRect().top - navbar.scrollTop + 'px';
}
if ((window.innerHeight - navbar.getBoundingClientRect().bottom) >= 0) {
document.body.style.overflow = 'hidden';
navbar.style.overflow = 'auto';
navbar.style.top = 0;
navbar.classList.add('sticky');
stickTop = true;
}
if (navbar.scrollTop == 0) {
navbar.classList.remove('open');
navbar.style.overflow = 'hidden';
document.body.style.overflow = '';
stickTop = false;
navbar.classList.remove('sticky');
navbar.style.top = '';
navbar.style.transition = '.2s';
setTimeout(() => {
navbar.style.transition = '';
}, 200);
}
}
})
body {
font-family: sans-serif;
}
.navbar {
position: fixed;
top: calc(100vh - 50px);
height: 100vh;
left: 0;
width: 100%;
overflow: hidden;
}
.navbar.open {
top: 50vh;
}
.navcontent {
background: black;
width: 100%;
color: white;
}
.navcontent p {
margin: 0;
}
.navheader {
height: 50px;
width: 100%;
background: lightblue;
cursor: pointer;
top: 0;
position: sticky;
display: flex;
justify-content: center;
z-index: 1;
}
.navheader::before {
width: 50px;
height: 3px;
margin-top: 10px;
background: white;
border-radius: 3px;
content: '';
}
<div class="navbar">
<div class="navheader"></div>
<div class="navcontent"><p>S</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>E</p></div>
</div>
<div class="content">
<p>S</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>E</p>
</div>

Track position of other element

I have an inner circle which tracks the position of my pointer, Now I want the circle color to change when it hovers on the h2 tag.
can anyone help??
I have tried searching few places but all were on "mouseover".
note: only when the inner-circle hovers on h2 not the mouse pointer, the inner circle's color should change.
<!doctype>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Roll Over Eyes</title>
<style>
body
{
display: flex;
align-items: center;
justify-content: center;
height: 900px;
border: 1px solid black;
}
.main-circle
{
display: flex;
align-items: center;
justify-content: center;
position: relative;
height: 350px;
width: 350px;
border: 1px solid black;
border-radius: 10%;
}
#inner-circle
{
position: absolute;
height: 50px;
width: 50px;
border: 1px solid black;
border-radius: 50%;
background: #af4b23;
}
.message
{
display:none;
width: 75%;
}
</style>
</head>
<body>
<div class="main-circle">
<div id="inner-circle">
</div>
<h2 class="message">Your Outside the box</h2>
<h2 class="message">Your inside the box, now move the mouse to move the circle.</h2>
</div>
<script>
(function()
{
var ele= document.getElementById("inner-circle");
var hea= document.getElementsByClassName("message");
var body=document.body;
var height=body.clientHeight;
var width=body.clientWidth;
var move = function(event)
{
var x= event.clientX;
var y= event.clientY;
ele.style.left = ( x/width )*300;
ele.style.top = ( y/height )*300;
}
var display = function()
{
console.log("done");
hea[0].style.display="inline-block";
hea[1].style.display="none";
}
var hide = function()
{
console.log("done hiden");
hea[0].style.display="none";
hea[1].style.display="inline-block";
}
var effect = function()
{
ele.style.backgroundColor= "rgba(0,0,0,0.5)";
}
var deflt = function()
{
ele.style.backgroundColor= "#af4b23";
}
body.addEventListener("mousemove",function(){ move(event) },false);
body.addEventListener("mouseout",display,false);
body.addEventListener("mouseover",hide,false);
hea[1].addEventListener("mouseover",effect,false);
hea[1].addEventListener("mouseout",deflt,false);
})();
</script>
</body>
</html>
You can try this:
(function()
{
var ele= document.getElementById("inner-circle");
var hea= document.getElementsByClassName("message");
var body=document.body;
var height=body.clientHeight;
var width=body.clientWidth;
var move = function(event)
{
var x= event.clientX;
var y= event.clientY;
ele.style.left = ( x/width )*300;
ele.style.top = ( y/height )*300;
var e_pos = ele.getBoundingClientRect();
var h_pos = hea[1].getBoundingClientRect();
if(e_pos.bottom>=h_pos.top && e_pos.top<=h_pos.bottom && e_pos.right>=h_pos.left && e_pos.left<=h_pos.right){
ele.style.backgroundColor= "rgba(0,0,0,0.5)";
}else{
ele.style.backgroundColor= "#af4b23";
};
}
var display = function()
{
//console.log("done");
hea[0].style.display="inline-block";
hea[1].style.display="none";
}
var hide = function()
{
//console.log("done hiden");
hea[0].style.display="none";
hea[1].style.display="inline-block";
}
body.addEventListener("mousemove",function(){ move(event) },false);
body.addEventListener("mouseout",display,false);
body.addEventListener("mouseover",hide,false);
})();
in this answer i set background-color after setting left and top of ele. also i have removed two last eventListeners.
Look at the result online and change it yorself!
the border is added to detect h2's bounds.

JavaScript script that only work on chrome, not working in Firefox. (Script for dragging div)

May be this is small question. But I couldn't found reason for this. I made a script to change a position of div by dragging it. the code is working fine with chrome browser. but when I trying to test it on Firefox it is not working.
var h = window.innerHeight|| document.documentElement.clientHeight || document.body.clientHeight;
window.onload = function () {
// ------------------lock the div with mouse pointer--------------
// variable dragged is for identified that you are click on the button or not
var dragged = false,
y = 0,pointerDis = 0,
boxElement = document.getElementById('drag'),
drgElement = document.getElementById('titl');
if (boxElement) {
// -----------------check whether the title div is holding by the mouse to lock it with mouse-------
drgElement.addEventListener('mousedown', function() {
dragged = true;
pointerDis = event.clientY - parseInt(window.getComputedStyle(boxElement, null).getPropertyValue("top"));
});
//------------------check whether the title div is released to drop the div-------------------------
document.addEventListener('mouseup', function() {
dragged = false;
});
document.addEventListener('mousemove', function () {
y = event.clientY;
if(dragged == true)
{
y = y -pointerDis;
if(y<0)
{
y = 0;
}
else if(y > window.innerHeight - boxElement.offsetHeight)
{
y = window.innerHeight - boxElement.offsetHeight;
}
boxElement.style.top = y + 'px';
}
});
}
};
.drg {
position: absolute;
top:0;
right: 0;
background: red;
border-top-left-radius: 45px;
border-bottom-left-radius: 45px;
}
#titl{
background: blue;
width: 50px;
text-align: center;
color: white;
font-size: 30px;
border-top-left-radius: 10px;
}
#det{
background: #f9c500;
width: 50px;
border-bottom-left-radius: 10px;
text-align: center;
}
<!DOCTYPE html>
<html>
<head>
<title>test 4</title>
</head>
<body>
<div class = "drg" id="drag">
<div id="titl" unselectable="on" onselectstart="return false;">....</div>
<div id="det">this is the details menu</div>
</div>
</body>
</html>
You can drag it through Y axis by click and drag from blue div. I don't know the reason or I couldn't find a way to fix this work on Firefox. Please help me!
You have to catch the (mousemove or mousedown) events as the input of wrapped functions
drgElement.addEventListener('mousedown', function(event)...
var h = window.innerHeight|| document.documentElement.clientHeight || document.body.clientHeight;
window.onload = function () {
// ------------------lock the div with mouse pointer--------------
// variable dragged is for identified that you are click on the button or not
var dragged = false,
y = 0,pointerDis = 0,
boxElement = document.getElementById('drag'),
drgElement = document.getElementById('titl');
if (boxElement) {
// -----------------check whether the title div is holding by the mouse to lock it with mouse-------
drgElement.addEventListener('mousedown', function(event) {
dragged = true;
pointerDis = event.clientY - parseInt(window.getComputedStyle(boxElement, null).getPropertyValue("top"));
});
//------------------check whether the title div is released to drop the div-------------------------
document.addEventListener('mouseup', function() {
dragged = false;
});
document.addEventListener('mousemove', function (event) {
y = event.clientY;
if(dragged == true)
{
y = y -pointerDis;
if(y<0)
{
y = 0;
}
else if(y > window.innerHeight - boxElement.offsetHeight)
{
y = window.innerHeight - boxElement.offsetHeight;
}
boxElement.style.top = y + 'px';
}
});
}
};
.drg {
position: absolute;
top:0;
right: 0;
background: red;
border-top-left-radius: 45px;
border-bottom-left-radius: 45px;
}
#titl{
background: blue;
width: 50px;
text-align: center;
color: white;
font-size: 30px;
border-top-left-radius: 10px;
}
#det{
background: #f9c500;
width: 50px;
border-bottom-left-radius: 10px;
text-align: center;
}
<!DOCTYPE html>
<html>
<head>
<title>test 4</title>
</head>
<body>
<div class = "drg" id="drag">
<div id="titl" unselectable="on" onselectstart="return false;">....</div>
<div id="det">this is the details menu</div>
</div>
</body>
</html>

Categories

Resources