Semi-fixed text in a scrolling container - javascript

I've got a bunch of horizontal boxes containing text. The boxes are all in a horizontally scrolling container:
// generate some random data
var model = {
leftEdge: ko.observable(0)
};
model.rows = populateArray(10 + randInt(20), randRow);
ko.applyBindings(model);
$(function() {
$('.slide').on('scroll', function() {
model.leftEdge(this.scrollLeft);
})
})
function randRow() {
var events = populateArray(50 + randInt(100), randEvent);
var left = randInt(1000);
events.forEach(function(event) {
event.left = left;
left += 10 + event.width + randInt(1000);
});
return {
events: events
}
}
function randEvent() {
var word = randWord()
var width = 50 + Math.max(8 * word.length, randInt(200));
var event = {
left: 0,
width: width,
label: word
};
event.offset = ko.computed(function() {
// reposition the text to stay
// * within its container
// * fully on-screen (if possible)
var leftEdge = model.leftEdge();
return Math.max(0, Math.min(
leftEdge - event.left,
event.width - 8 * event.label.length
));
});
return event;
}
function randWord() {
var n = 2 + randInt(5);
var ret = "";
while (n-- > 0) {
ret += randElt("rmhntsk");
ret += randElt("aeiou");
}
return ret;
}
function randElt(arr) {
return arr[randInt(arr.length)];
}
function populateArray(n, populate) {
var arr = new Array(n);
for (var i = 0; i < n; i++) {
arr[i] = populate();
}
return arr;
}
function randInt(n) {
return Math.floor(Math.random() * n);
}
.slide {
max-width: 100%;
overflow: auto;
border: 5px solid black;
}
.row {
position: relative;
height: 25px;
}
.event {
position: absolute;
top: 2.5px;
border: 1px solid black;
padding: 2px;
background: #cdffff;
font-size: 14px;
font-family: monospace;
}
.event > span {
position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div class="slide" data-bind="foreach: rows">
<div class="row" data-bind="foreach: events">
<div class="event" data-bind="style: { left: left+'px', width: width+'px' }"><span data-bind="text:label, style: { left: offset() + 'px' }"></div>
</div>
</div>
What I'd like to do is as the user scrolls from left-to-right, reposition the text within each box that partially overlaps the left border of the visible window to keep the text as visible as possible.
Currently I'm doing this by manually repositioning each item of text.
Is there a cleaner way to do this using CSS?

A friend helped me come up with this solution.
In English, the idea is to add an overlay to each row that is positioned relatively to the frame of the scrolling box, rather than the contents.
Then we can place a label for any box that overlaps the left edge in this overlay and it will appear to smoothly move as the box underneath it scrolls.
// generate some random data
var model = {
leftEdge: ko.observable(0),
};
model.rows = populateArray(10 + randInt(20), randRow);
model.width = Math.max.apply(Math, $.map(model.rows, function(row) {
return row.width
}));
ko.applyBindings(model);
$(function() {
$('.slide').on('scroll', function() {
model.leftEdge(this.scrollLeft);
})
})
function randRow() {
var events = populateArray(50 + randInt(100), randEvent);
var left = randInt(1000);
events.forEach(function(event) {
event.left = left;
left += 10 + event.width + randInt(1000);
});
return {
events: events,
width: left
}
}
function randEvent() {
var word = randWord()
var width = 50 + Math.max(8 * word.length, randInt(200));
var event = {
width: width,
label: word,
};
event.tense = ko.computed(function() {
// reposition the text to stay#
// * within its container
// * fully on-screen (if possible)
var leftEdge = model.leftEdge();
return ['future', 'present', 'past'][
(leftEdge >= event.left) +
(leftEdge > event.left + event.width - 8 * event.label.length)
];
});
return event;
}
function randWord() {
var n = 2 + randInt(5);
var ret = "";
while (n-- > 0) {
ret += randElt("rmhntsk");
ret += randElt("aeiou");
}
return ret;
}
function randElt(arr) {
return arr[randInt(arr.length)];
}
function populateArray(n, populate) {
var arr = new Array(n);
for (var i = 0; i < n; i++) {
arr[i] = populate();
}
return arr;
}
function randInt(n) {
return Math.floor(Math.random() * n);
}
.wrapper {
position: relative;
border: 5px solid black;
font-size: 14px;
font-family: monospace;
}
.slide {
max-width: 100%;
overflow: auto;
}
.slide > * {
height: 25px;
}
.overlay {
position: absolute;
width: 100%;
left: 0;
}
.overlay .past {
display: none
}
.overlay .present {
position: absolute;
z-index: 1;
top: 5.5px;
left 0;
}
.overlay .future {
display: none
}
.row {
position: relative;
}
.event {
position: absolute;
top: 2.5px;
border: 1px solid black;
padding: 2px;
background: #cdffff;
height: 14px;
}
.event .past {
float: right;
}
.event .present {
display: none;
}
.event .future {
float: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div class="wrapper">
<div class="slide" data-bind="foreach: rows, style: { width: width + 'px' }">
<div class="overlay" data-bind="foreach: events">
<span data-bind="text:label, css: tense"></span>
</div>
<div class="row" data-bind="foreach: events">
<div class="event" data-bind="style: { left: left+'px', width: width+'px' }"><span data-bind="text:label, css: tense"></div>
</div>
</div></div>
This doesn't result in less javascript, but it does result in more efficient javascript, as class changes happen much less often than offset changes, so fewer updates to DOM elements are required.
You can avoid processing every "event" (in the above example) by doing some pre-partitioning of the horizontal space, and only updating events in the relevant partition.

Related

Javascript carosel animation

I'm trying to make an image carousel with center animation. I don't want to use CSS animations, instead I'd like to use jQuery.
By pressing the 'Prev' button the animation will start. One of the slides which will be central begins to grow. I've used jQuery's animate() to animate width and height. Everything works as required except I can't understand why the animation makes the central slide jump.
I have created this sample. If you push the 'Prev' button the animation will start.
var scroll_speed = 4000;
var items_cnt = $('.mg_item').length;
var container_size = $(".main_cnt").innerWidth();
var item_avg_w = container_size / 5;
var item_center_w = ((item_avg_w / 100) * 20) + item_avg_w;
var item_center_h = (item_center_w / 16) * 9 + 30;
var item_w = ((container_size - item_center_w) / 4) - 2;
var item_h = ((item_w / 16) * 9);
var gallery_content = $('.gallery_body').html();
$('.gallery_body').html(gallery_content + gallery_content + gallery_content);
var items_offset = items_cnt * item_w + 14;
$('.gallery_body').css('left', -items_offset);
$('.mg_item').css("width", item_w);
$('.mg_item').css("height", item_h);
//$('.mg_item').css("margin-bottom", (item_center_h - item_h) / 2);
//$('.mg_item').css("margin-top", (item_center_h - item_h) / 2);
//$('.mg_item_с').css("width", item_center_w);
//$('.mg_item_с').css("height", item_center_h);
//document.documentElement.style.setProperty('--center_width', item_center_w + "px");
//document.documentElement.style.setProperty('--center_height', item_center_h + "px");
$('.main_cnt').css("height", item_center_h);
check_visible();
AssignCenter(0);
function gonext() {
AssignCenter(-1);
ZoomIn();
$('.gallery_body').animate({
left: '+=' + (item_w + 2),
}, scroll_speed, "linear", function() {
LoopSlides();
});
}
function goprev() {
AssignCenter(1);
ZoomIn();
$('.gallery_body').animate({
left: '-=' + (item_w + 2),
}, scroll_speed, "linear", function() {
LoopSlides();
});
}
function ZoomIn() {
$('.center').animate({
width: item_center_w + 'px',
height: item_center_h + 'px',
}, scroll_speed, function() {});
}
function LoopSlides() {
var cur_pos = $('.gallery_body').position().left
var left_margin = Math.abs(items_offset * 2 - item_w) * -1;
var right_margin = 0 - item_w;
if (cur_pos < left_margin) {
$('.gallery_body').css('left', -items_offset);
}
if (cur_pos >= 0) {
$('.gallery_body').css('left', -items_offset);
}
check_visible();
AssignCenter(0);
}
function check_visible() {
$('.mg_item').each(function(i, obj) {
var pos = $(this).offset().left;
if (pos < 0 || pos > container_size) {
$(this).addClass("invisible");
$(this).removeClass("active");
} else {
$(this).addClass("active");
$(this).removeClass("invisible");
}
});
}
function AssignCenter(offset) {
var center_slide = $('.active')[2 + offset];
$('.center').each(function(i, obj) {
$(this).removeClass("center");
});
$(center_slide).addClass("center");
//$(center_slide).css("width", item_center_w);
//$(center_slide).css("height", item_center_h);
}
:root {
--center_width: 0px;
--center_height: 0px;
}
.main_cnt {
background-color: rgb(255, 0, 0);
padding: 0px;
overflow: hidden;
margin: 0px;
}
.gallery_body {
width: 500%;
background-color: rgb(128, 128, 128);
position: relative;
}
.mg_item {
width: 198px;
height: 150px;
background-color: blue;
display: inline-block;
position: relative;
margin: -1px;
padding: 0px;
font-size: 120px;
}
.center {
background-color: brown;
/*width: var(--center_width) !important;
height: var(--center_height) !important;*/
}
.item_c {
width: 410px;
height: 150px;
background-color: blueviolet;
display: inline-block;
position: relative;
margin: -1px;
padding: 0px;
font-size: 120px;
}
.video-js .vjs-dock-text {
text-align: right;
}
<script src="https://code.jquery.com/jquery-2.2.0.min.js" type="text/javascript"></script>
<div class="main_cnt">
<div class="gallery_body">
<div class="mg_item">1</div>
<div class="mg_item">2</div>
<div class="mg_item">3</div>
<div class="mg_item">4</div>
<div class="mg_item">5</div>
<div class="mg_item">6</div>
<div class="mg_item">7</div>
</div>
</div>
<br><br>
<button onclick="gonext()">GONEXT</button>
<button onclick="goprev()">GOPREV</button>
<button onclick="check_visible()">CHEVIS</button>

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>

Check if DOM elements are present inside a DIV then run functions assigned to those elements in order

i'm trying to develop a game using html, css and js. At the moment I'm focusing on manipulating DOM elements without using the canvas tag. My idea is to create a pseudo graphical programming language, similar to the Blockly environment. So far I have inserted 3 clickable elements inside #toolbox that create their copies in #workspace.
Now, I am trying to assign functions to the elements present in #workspace, which once pressed the Run button are executed in order of appearance, so as to create a queue of commands that is able to move the pink square inside #output_section.
Therefore I cannot understand how to write the function that is able to verify the presence of the elements and then be able to perform the different functions assigned to these elements.
Any ideas? :D
I'm using Jquery 3.3.1
function addRed() {
var redWorkspace = document.createElement("DIV");
redWorkspace.className = "remove-block block red";
document.getElementById("workspace").appendChild(redWorkspace);
};
function addBlue() {
var blueWorkspace = document.createElement("DIV");
blueWorkspace.className = "remove-block block blue";
document.getElementById("workspace").appendChild(blueWorkspace);
};
function addGreen() {
var greenWorkspace = document.createElement("DIV");
greenWorkspace.className = "remove-block block green";
document.getElementById("workspace").appendChild(greenWorkspace);
};
$("#clear_workspace").click(function () {
$("#workspace").empty();
});
$(document).on("click", ".remove-block", function () {
$(this).closest("div").remove();
});
html,
body {
margin: 0;
padding: 0;
}
#workspace {
display: flex;
height: 100px;
padding: 10px;
background: black;
}
#toolbox {
display: flex;
padding: 10px;
width: 300px;
}
#output_section {
height: 500px;
width: 500px;
border: solid black;
margin: 10px;
position: relative;
}
#moving_square {
position: absolute;
bottom: 0;
right: 0;
width: 100px;
height: 100px;
background: pink;
}
.block {
height: 100px;
width: 100px;
}
.red {
background: red;
}
.blue {
background: cyan;
}
.green {
background: green;
}
.grey {
background: #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<body>
<div id="workspace"></div>
<div id="workspace-menu">
<button id="run_workspace">Run</button>
<button id="clear_workspace">Clear</button>
</div>
<div id="toolbox" class="grey">
<div onclick="addRed()" class="block red">Left</div>
<div onclick="addBlue()" class="block blue">Up</div>
<div onclick="addGreen()" class="block green">Right</div>
</div>
<div id="output_section">
<div id="moving_square"></div>
</div>
</body>
</html>
Completely untested but run button does something along the lines of:
$("#run_workspace").click(function() {
$("#workspace .block").each(function(elem) {
if (elem.hasClass("red")) {
moveObjectLeft();
} else if (elem.hasClass("green")) {
moveObjectRight();
} else if (elem.hasClass("blue")) {
moveObjectUp();
}
});
});
Commonly, it's a good idea to store all required information in arrays and objects, and use HTML only to display your data.
Also, if you are already using jQuery - use it for all 100%)
Made some improvements:
let mobs = {
pinky: {
node: $('#moving_square'),
coors: { top: 400, left: 400 },
step: 30,
moveQueue: [],
// moveTimeout ???
},
}; // storing here all created objects, that must move.
/* Each [moveQueue] array will store the chain of moves, like ["up", "up", "left"]
You can take each "key-word" of move, and get required function buy that key,
from the 'move' object */
let move = { // Think about how to simlify this object and functions. It's possible!)
left: function (obj) {
let left = obj.coors.left = (obj.coors.left - obj.step);
obj.node.css('left', left + 'px');
},
up: function (obj) {
let top = obj.coors.top = (obj.coors.top - obj.step);
obj.node.css('top', top + 'px');
},
right: function (obj) {
let left = obj.coors.left = (obj.coors.left + obj.step);
obj.node.css('left', left + 'px');
}
};
let stepTimeout = 1000;
let running = false;
let timeouts = {}; // store all running timeouts here,
// and clear everything with for( key in obj ) loop, if required
$('#toolbox .block').on('click', function () {
let color = $(this).attr('data-color');
let workBlock = '<div class="remove-block block ' + color + '"></div>';
$('#workspace').append(workBlock);
mobs.pinky.moveQueue.push( $(this).text().toLowerCase() ); // .attr('data-direction');
// instead of pinky - any other currently selected object
// $(this).text().toLowerCase() — must be "left", "up", "right"
});
$('#run_workspace').on('click', function () {
running = true;
runCode();
function runCode() {
for (let obj in mobs) { // mobile objects may be multiple
// Inside the loop, obj == mobs each key name. Here it's == "pinky"
let i = 0;
let pinky = mobs[obj];
localRun();
function localRun() {
let direction = pinky.moveQueue[i]; // getting direction key by array index.
move[direction](pinky); // calling the required function from storage.
if (pinky.moveQueue[++i] && running ) {
// self-calling again, if moveQueue has next element.
// At the same time increasing i by +1 ( ++i )
timeouts[obj] = setTimeout(localRun, stepTimeout);
}
}
}
}
});
$("#clear_workspace").click(function () {
$("#workspace").empty();
});
$('#workspace').on("click", ".remove-block", function () {
$(this).closest("div").remove();
});
html,
body {
margin: 0;
padding: 0;
}
#workspace {
display: flex;
height: 100px;
padding: 10px;
background: black;
}
#toolbox {
display: flex;
padding: 10px;
width: 300px;
}
#output_section {
height: 500px;
width: 500px;
border: solid black;
margin: 10px;
position: relative;
}
#moving_square {
position: absolute;
top: 400px;
left: 400px;
width: 100px;
height: 100px;
background: pink;
}
.block {
height: 100px;
width: 100px;
}
.red {
background: red;
}
.blue {
background: cyan;
}
.green {
background: green;
}
.grey {
background: #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="workspace"></div>
<div id="workspace-menu">
<button id="run_workspace">Run</button>
<button id="clear_workspace">Clear</button>
</div>
<div id="toolbox" class="grey">
<div data-color="red" class="block red">Left</div>
<div data-color="blue" class="block blue">Up</div>
<div data-color="green" class="block green">Right</div>
</div>
<div id="output_section">
<div id="moving_square"></div>
</div>
But... jQuery was used only for clicks... Translation to JS:
let mobs = {
pinky: {
node: document.getElementById('moving_square'),
coors: { top: 400, left: 400 },
step: 30,
moveQueue: [],
},
};
let move = {
left: function (obj) {
let left = obj.coors.left = (obj.coors.left - obj.step);
obj.node.style.left = left + 'px';
},
up: function (obj) {
let top = obj.coors.top = (obj.coors.top - obj.step);
obj.node.style.top = top + 'px';
},
right: function (obj) {
let left = obj.coors.left = (obj.coors.left + obj.step);
obj.node.style.left = left + 'px';
}
};
let stepTimeout = 1000;
let running = false;
let timeouts = {};
let blocks = document.querySelectorAll('#toolbox .block');
let workSpace = document.getElementById('workspace');
blocks.forEach(function(block){
block.addEventListener('click', function(){
let color = this.dataset.color;
let workBlock = '<div class="remove-block block ' + color + '"></div>';
workSpace.insertAdjacentHTML('beforeend', workBlock);
mobs.pinky.moveQueue.push( this.textContent.toLowerCase() );
});
});
document.getElementById('run_workspace').addEventListener('click', function () {
running = true;
runCode();
function runCode() {
for (let obj in mobs) { // mobile objects may be multiple
// Inside the loop, obj == mobs each key name. Here it's == "pinky"
let i = 0;
let pinky = mobs[obj];
localRun();
function localRun() {
let direction = pinky.moveQueue[i]; // getting direction key by array index.
move[direction](pinky); // calling the required function from storage.
if (pinky.moveQueue[++i] && running ) {
// self-calling again, if moveQueue has next element.
// At the same time increasing i by +1 ( ++i )
timeouts[obj] = setTimeout(localRun, stepTimeout);
}
}
}
}
});
document.getElementById("clear_workspace").addEventListener('click', function () {
workSpace.textContent = "";
});
workSpace.addEventListener('click', function (e) {
if( e.target.classList.contains('remove-block') ){
e.target.remove();
}
});
html,
body {
margin: 0;
padding: 0;
}
#workspace {
display: flex;
height: 100px;
padding: 10px;
background: black;
}
#toolbox {
display: flex;
padding: 10px;
width: 300px;
}
#output_section {
height: 500px;
width: 500px;
border: solid black;
margin: 10px;
position: relative;
}
#moving_square {
position: absolute;
top: 400px;
left: 400px;
width: 100px;
height: 100px;
background: pink;
}
.block {
height: 100px;
width: 100px;
}
.red {
background: red;
}
.blue {
background: cyan;
}
.green {
background: green;
}
.grey {
background: #ccc;
}
<div id="workspace"></div>
<div id="workspace-menu">
<button id="run_workspace">Run</button>
<button id="clear_workspace">Clear</button>
</div>
<div id="toolbox" class="grey">
<div data-color="red" class="block red">Left</div>
<div data-color="blue" class="block blue">Up</div>
<div data-color="green" class="block green">Right</div>
</div>
<div id="output_section">
<div id="moving_square"></div>
</div>

Make navigation clickable in fullpage script

I have a simple project based on one variation of fullpage script. Everything works perfect except for one annoying thing - I can't understand how to make my right navigation bullets clickable (to an appropriate section). My js knowledge is not too good at the moment so I'd really appreciate any help, guys. Thanks!
$.fullPage = function(option) {
var defaultOpt = {
box: "#fullPageBox", // 滚屏页父元素
page: ".fullPage", // 滚屏页面
index: true, // 是否显示索引
duration: 1000, // 动画时间
direction: "vertical", // 滚屏方向 horizontal or vertical
loop: true // 是否循环
},
This = this,
index = 0,
over = true;
this.option = $.extend({}, defaultOpt, option || {});
this.box = $(this.option.box);
this.pages = $(this.option.page);
this.duration = this.option.duration;
// 绑定鼠标滚轮事件
$(document).on("mousewheel DOMMouseScroll", function(ev) {
var dir = ev.originalEvent.wheelDelta || -ev.originalEvent.detail;
if (over === false) return;
dir < 0 ? nextPage() : prevPage();
});
if (this.option.index) {
initPagination();
};
function initPagination() {
var oUl = $("<ul id='fullPageIndex'></ul>"),
liStr = "";
for (var i = 0, len = This.pages.length; i < len; i++) {
liStr += "<li></li>";
};
$(document.body).append(oUl.append($(liStr)));
$("#fullPageIndex li").eq(index).addClass("active").siblings().removeClass("active");
};
function nextPage() {
if (index < This.pages.length - 1) {
index++;
} else {
index = 0;
}
scrollPage(index, This.pages.eq(index).position());
};
function prevPage() {
if (index === 0) {
index = This.pages.length - 1;
} else {
index--;
}
scrollPage(index, This.pages.eq(index).position());
};
function scrollPage(index, position) {
over = false;
var cssStr = This.option.direction === "vertical" ? {
top: -position.top
} : {
left: -position.left
};
This.box.animate(cssStr, This.duration, function() {
over = true;
})
$("#fullPageIndex li").eq(index).addClass("active").siblings().removeClass("active");
};
}
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
overflow: hidden;
}
.pageBox {
position: relative;
height: 100%;
}
.main {
width: 100%;
height: 500%;
min-width: 1200px;
position: absolute;
left: 0;
top: 0;
color: #fff;
}
.main .fullPage {
height: 25%;
}
.bg1 {
background-color: #27AE60;
}
.bg2 {
background-color: #3498DB;
}
.bg3 {
background-color: #C0392B;
}
.bg4 {
background-color: #4FC2E5;
}
.bg5 {
background-color: #8E44AD;
}
#fullPageIndex {
position: absolute;
top: 50%;
right: 20px;
transform: translateY(-50%);
}
#fullPageIndex li {
width: 10px;
height: 10px;
list-style: none;
background-color: black;
margin: 6px 0;
border-radius: 50%;
}
#fullPageIndex li.active {
background-color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<div class="pageBox">
<div class="main" id="fullPageBox">
<div class="fullPage bg1">jQuery fullPage.js</div>
<div class="fullPage bg2">Section 2</div>
<div class="fullPage bg3">Section 3</div>
<div class="fullPage bg4">Section 4</div>
<div class="fullPage bg5">Section 5</div>
</div>
</div>
<script>
$.fullPage();
</script>
</body>
Add an id attribute to you divs and add an anchor to the list elements that navigate to the desired sections. As follows:
<body>
<div class="pageBox">
<div class="main" id="fullPageBox">
<div id="section1" class="fullPage bg1">jQuery fullPage.js</div>
<div id="section2" class="fullPage bg2">Section 2</div>
<div id="section3" class="fullPage bg3">Section 3</div>
<div id="section4" class="fullPage bg4">Section 4</div>
<div id="section5" class="fullPage bg5">Section 5</div>
</div>
</div>
<script>
$.fullPage();
</script>
</body>
Update your js where you render the list items to look like this:
function initPagination() {
var oUl = $("<ul id='fullPageIndex'></ul>"),
liStr = "";
for (var i = 0, len = This.pages.length; i <= len; i++) {
var sectionNum = i + 1;
liStr += '<li></li>';
};
$(document.body).append(oUl.append($(liStr)));
$("#fullPageIndex li").eq(index).addClass("active").siblings().removeClass("active");
};
Read more here
EDIT:
Since you asked for a smooth scroll as well you could add this to your JS:
$('a[href*=#]:not([href=#])').click(function() {
if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'')
|| location.hostname == this.hostname) {
var target = $(this.hash);
target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top
}, 1000);
return false;
}
}
});
Source for the snippet can be found on this page.
there is some mistake in your script.
First, remove below code from your HTML file:
<script>
fullPage();
</script>
Second is, you've created wrong function (method) define. I'am replace $.fullpage = function(option) { with var fullpage = function(options) {
and for the last is: since we have removed your fullpage() initiator, so we need to call this method again. for example at end line of your JS file,
P.S:
In Javascript you can create function in several ways. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions for more detail.
See fixed code below:
var fullPage = function(option) {
var defaultOpt = {
box: "#fullPageBox", // 滚屏页父元素
page: ".fullPage", // 滚屏页面
index: true, // 是否显示索引
duration: 1000, // 动画时间
direction: "vertical", // 滚屏方向 horizontal or vertical
loop: true // 是否循环
},
This = this,
index = 0,
over = true;
this.option = $.extend({}, defaultOpt, option || {});
this.box = $(this.option.box);
this.pages = $(this.option.page);
this.duration = this.option.duration;
// 绑定鼠标滚轮事件
$(document).on("mousewheel DOMMouseScroll", function(ev) {
var dir = ev.originalEvent.wheelDelta || -ev.originalEvent.detail;
if (over === false) return;
dir < 0 ? nextPage() : prevPage();
});
if (this.option.index) {
initPagination();
};
function initPagination() {
var oUl = $("<ul id='fullPageIndex'></ul>"),
liStr = "";
for (var i = 0, len = This.pages.length; i < len; i++) {
liStr += "<li></li>";
};
$(document.body).append(oUl.append($(liStr)));
$("#fullPageIndex li").eq(index).addClass("active").siblings().removeClass("active");
};
function nextPage() {
if (index < This.pages.length - 1) {
index++;
} else {
index = 0;
}
scrollPage(index, This.pages.eq(index).position());
};
function prevPage() {
if (index === 0) {
index = This.pages.length - 1;
} else {
index--;
}
scrollPage(index, This.pages.eq(index).position());
};
function scrollPage(index, position) {
over = false;
var cssStr = This.option.direction === "vertical" ? {
top: -position.top
} : {
left: -position.left
};
This.box.animate(cssStr, This.duration, function() {
over = true;
})
$("#fullPageIndex li").eq(index).addClass("active").siblings().removeClass("active");
};
}
fullPage();
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
overflow: hidden;
}
.pageBox {
position: relative;
height: 100%;
}
.main {
width: 100%;
height: 500%;
min-width: 1200px;
position: absolute;
left: 0;
top: 0;
color: #fff;
}
.main .fullPage {
height: 25%;
}
.bg1 {
background-color: #27AE60;
}
.bg2 {
background-color: #3498DB;
}
.bg3 {
background-color: #C0392B;
}
.bg4 {
background-color: #4FC2E5;
}
.bg5 {
background-color: #8E44AD;
}
#fullPageIndex {
position: absolute;
top: 50%;
right: 20px;
transform: translateY(-50%);
}
#fullPageIndex li {
width: 10px;
height: 10px;
list-style: none;
background-color: black;
margin: 6px 0;
border-radius: 50%;
}
#fullPageIndex li.active {
background-color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<body>
<div class="pageBox">
<div class="main" id="fullPageBox">
<div class="fullPage bg1">jQuery fullPage.js</div>
<div class="fullPage bg2">Section 2</div>
<div class="fullPage bg3">Section 3</div>
<div class="fullPage bg4">Section 4</div>
<div class="fullPage bg5">Section 5</div>
</div>
</div>
</body>

How to rollover text on images dynamically using javascript/jquery

I am new to web development but highly fascinated by it. So, basically I am creating a light-box where thumbnails of images will be appear on screen and they will appear bigger in size when user clicks over them. Now, I want when user hovers over the gallery images/thumbnails then some text should appear over the current image with may be some animation or basically mouser-hover should cause some event to happen but I am unable to do it. Text should be added dynamically or may be previously stored in an array or something of that sort. Please have a look at my code and tell me how to modify it in order to achieve such effect and if you know a better and easier way to do so then feel free to share. Thank you so much!!
HTML:
<div class="gallery">
<ul id="images"></ul>
<div class="lightbox">
<div class='limage'>
</div>
<div class='left'>
</div>
<div class='right'>
</div>
<div class='close'>
x
</div>
</div>
</div>
JAVASCRIPT:
var gallery_slider = new Array();
gallery_slider[0] = "im1.jpg";
gallery_slider[1] = "im2.jpg";
gallery_slider[2] = "im3.jpg";
function displayAllImages() {
var i = 0,
len = gallery_slider.length;
for (; i < gallery_slider.length; i++) {
var img = new Image();
img.src = gallery_slider[i];
img.style.width = '200px';
img.style.height = '120px';
img.style.margin = '3px';
img.style.cursor = 'pointer';
document.getElementById('images').appendChild(img);
}
};
$(function() {
displayAllImages();
});
$(function() {
$('img').click(function() {
var hell = (this).src;
display(hell);
});
});
function display(hello) {
$('header').css('display', 'none'); /*for some other purposes*/
$('.limage').html("<img src=" + hello + " >");
$('.lightbox').css("display", "block");
$('.lightbox').fadeIn();
$('.right').click(function() {
var im = new Array();
var x;
var p;
for (x = 0; x < gallery_slider.length; x++) {
im[x] = gallery_slider[x];
}
for (p = 0; p < im.length; p++) {
if (im[p] == hello) {
break;
} else {
continue;
}
}
if (p >= (im.length - 1)) {
p = -1;
}
$('.limage').fadeOut(0);
$('.limage').html("<img src= " + im[p + 1] + ">");
$('.limage').fadeIn(500);
hello = im[p + 1];
});
$('.left').click(function() {
var im = new Array();
var x;
var p;
for (x = 0; x < gallery_slider.length; x++) {
im[x] = gallery_slider[x];
}
for (p = 0; p < im.length; p++) {
if (im[p] == hello) {
break;
} else {
continue;
}
}
if (p == 0) {
p = (im.length);
}
$('.limage').fadeOut(0);
$('.limage').html("<img src= " + im[p - 1] + ">");
$('.limage').fadeIn(500);
hello = im[p - 1];
});
$('.close').click(function() {
$('.lightbox').fadeOut();
$('header').css('display', 'block'); /*for some other purposes*/
});
};
CSS:
.gallery {
width: 100%;
height: 400px;
overflow: hidden;
margin: auto;
}
.gallery ul {
list-style: none;
}
.lightbox {
background-color: rgba(0, 0, 0, 0.3);
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: none;
z-index: 106;
}
.close {
color: #fff;
border: 1px solid #fff;
border-radius: 100px;
background-color: #000;
position: absolute;
top: 10px;
right: 20px;
padding: 10px;
font-family: firstfont;
font-size: 30px;
z-index: 101;
cursor: pointer;
}
.close:hover {
background-color: #ebebeb;
color: #000;
}
.left {
width: 50%;
height: 100%;
position: absolute;
top: 0;
left: 0;
cursor: pointer;
}
.right {
width: 50%;
height: 100%;
position: absolute;
top: 0;
right: 0;
cursor: pointer;
}
.limage {
position: relative;
margin: auto;
top: 17%;
left: 15%;
max-width: 90%;
max-height: 90%;
}
There might be some bugs in coding. Watch out.
This code is working for displaying images as thumbnails as a matrix and as slider in lightbox when clicked upon them. I am not able to figure out how to add hover functionality to initial thumbnails.
Jsfiddle :
http://jsfiddle.net/psd6cbd7/1/
I'd suggest putting a div inside the image div containing the text and then using CSS to hide/show it.
HTML:
<div class="gallery">
<ul id="images"></ul>
<div class="lightbox">
<div class='limage'>
<div class=".caption">Caption here</div>
</div>
<div class='left'>
</div>
<div class='right'>
</div>
<div class='close'>
x
</div>
</div>
</div>
CSS:
.limage { position: relative; }
.caption { display: none; }
.limage:hover .caption { display: block; position: absolute;}
Why you using array to store the images? Anyways, assume that you still using array, below is some example code that you want try:
HTML:
<ul id="images">
</ul>
<!-- assume this is the place that you want to display the caption -->
<div id="caption"></div>
Javascript:
var images = new Array();
images[0] = "p1.png";
images[1] = "p2.png";
images[2] = "p3.png";
images[3] = "p4.png";
var captions = new Array();
captions[0] = "Picture 1";
captions[1] = "Picture 2";
captions[2] = "Picture 3";
captions[3] = "Picture 4";
var x = $("#images");
var y = $("#caption");
const prefix = "image-";
if you are using HTML5:
for (var i = 0; i < images.length; i++) {
x.append("<img class='roll' src='" + images[i] + "' data-caption='" + captions[i] + "'>");
}
$(".roll").mouseover(function(){
//do whatever effect here when mouse over
y.html($(this).attr("data-caption"));
});
If you want to backward compatible:
for (var i = 0; i < images.length; i++) {
x.append("<img id='" + prefix + i + "' class='roll' src='" + images[i] + "'>");
}
$(".roll").mouseover(function(){
//do whatever effect here when mouse over
var index = $(this).attr("id").substring(prefix.length);
y.html(captions[index]);
});
Hope that this will help.

Categories

Resources