JavaScript style.height of sister div on mouseover - javascript

I'm trying to simulate the look of an audio visualizer so that on mouseover, "this" div becomes the tallest div, while the sister divs shift heights as well. How do I specify which height the sister divs should change to?
Code
window.onload = window.onscroll = function() {
var bars = document.getElementsByClassName('bar');
[].forEach.call(bars, function(bar) {
bar.style.height = Math.random() * 50 + '%';
});
}
.bars {
position: fixed;
top: 30px;
right: 0;
bottom: 40px;
left: 0;
margin: 10px auto;
text-align: center
}
.bars::before {
content: "";
display: inline-block;
height: 100%;
}
.bar {
display: inline-block;
vertical-align: bottom;
width: 4rem;
height: 25%;
margin-right: .75em;
background: #333;
-webkit-transition: height 0.5s ease-out;
transition: height 0.5s ease-out;
}
<div class="container">
<div class="bars">
<div class="bar" id="barOne"></div>
<div class="bar" id="barTwo"></div>
<div class="bar" id="barThree"></div>
<div class="bar" id="barFour"></div>
<div class="bar" id="barFive"></div>
</div>
</div>
Thanks for your help!

Here's a fiddle that should get you pointed in the right direction: https://jsfiddle.net/8p2yvro9/7/
let container = document.getElementsByClassName('container')[0];
let bars = document.getElementsByClassName('bar');
[].forEach.call(bars, bar => {
bar.addEventListener('mouseover', function() {
shiftBars(bar);
});
});
function shiftBars(barOver) {
[].forEach.call(bars, function(bar) {
bar.style.height = Math.random() * 50 + '%';
});
barOver.style.height = '100%';
}

Related

How to make info text appear and follow the cursor when hovering over image?

For my portfolio website, I want to include info text that becomes visible when hovering over the according image and I want the text to follow along the cursor.
I'm by no means a coding expert, so I tried to achieve the effect by replacing the default cursor with an image of the text on white background via css and the cursor-property.
However, this left me with weird gray edged around the image that the image originally doesn't have.
So I figured that this was a sloppy approach anyway and that I should rather try solving it via javascript... which left me with the following code:
$(document).bind('mousemove', function(e){
$('#tail').css({
left: e.clientX + 20,
top: e.clientY + document.body.scrollTop
});
});
#tail {
position: absolute;
background-color: #ffffff;
padding: 5px;
opacity: 0;
}
#tail p {
margin: 0px;
}
.project-01:hover > #tail {
opacity: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="project-01">
<a href="project-site-01.html">
<img src="images/project-cover-01.png" alt="Project description">
</a>
<div id="tail">
<p>Project description</p>
</div>
</div>
I am now left with text that appears when hovering over the image and it follows the cursor properly, even if the cursor position changes due to scrolling (which it didn't do properly at first, which is why I added the 'document.body.scrollTop').
The only problem: The info text is way to far away from the cursor. I tried adjusting the offset, adding '- 900' after 'document.body.scrollTop' but that only makes it look right with my specific browser height – if I switch to a smaller or bigger screen, the '- 900' of course doesn't fit anymore.
Is there anyone who can explain what I'm doing wrong on a dummy level or even better – tell me how to fix the problem? I've been trying to get that hover text effect working for literally the past two days. HELP!
PS: You can see the effect I want to create on https://playgroundparis.com
I hope this can help you!
Edit: Technically this is a duplicated. I realized the problem with scrolling that you talking about. I've found a solution in this post and I readaptated it for
your specific case.
var mouseX = 0, mouseY = 0, limitX, limitY, containerWidth;
window.onload = function(e) {
var containerObjStyle = window.getComputedStyle(document.querySelectorAll(".project-01")[0]);
containerWidth = parseFloat(containerObjStyle.width).toFixed(0);
containerHeight = parseFloat(containerObjStyle.height).toFixed(0);
var follower = document.querySelector('#tail');
var xp = 0, yp = 0;
limitX = containerWidth;
limitY = containerHeight;
var loop = setInterval(function(){
//Change the value 5 in both axis to set the distance between cursor and text.
xp = (mouseX == limitX) ? limitX : mouseX + 5;
xp = (xp < 0) ? 0 : xp;
yp = (mouseY == limitY) ? limitY : mouseY + 5;
yp = (yp < 0) ? 0 : yp;
follower.style.left = xp + 'px';
follower.style.top = yp + 'px';
}, 15);
window.onresize = function(e) {
limitX = parseFloat(window.getComputedStyle(document.querySelectorAll(".project-01")[0]).width).toFixed(0);
}
document.onmousemove = function(e) {
mouseX = Math.min(e.pageX, limitX);
mouseY = Math.min(e.pageY, limitY);
}
};
//Change the 100 value to set the fade time (ms).
$(".project-01").hover(function () {
$(this).find('#tail').fadeIn(100);
},
function () {
$(this).find('#tail').fadeOut(100);
});
#tail {
position: absolute;
background-color: #ffffff;
padding: 5px;
overflow: hidden;
}
#debug {
position: absolute;
right: 0;
top: 100px;
width: 100px;
height:100px;
background-color: red;
color: black;
}
#tail p {
margin: 0px;
}
.project-01 {
width: 300px;
overflow: hidden;
}
.project-01 img {
height: 100%;
width: 100%;
}
.project-01 a {
height: 100%;
width: 100%;
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="project-01">
<a href="project-site-01.html">
<img src="https://picsum.photos/200/300" alt="Project description">
</a>
<div id="tail">
<p>Project descriptions</p>
</div>
</div>
You can use the below code's
.description {
display: none;
position: absolute;
z-index: 2000 !important;
color: black;
padding: 15px;
margin-left: 32px;
margin-top: -200px;
top: auto;
height: auto;
width: 500px;
}
.image {
height: 200px;
width: 200px;
}
.my-image:hover + .description {
display: block;
position: absolute;
background-color: black;
color: white;
}
.description:hover {
display: block;
background-color: black;
color: white;
}
<div class="project-01">
<a href="project-site-01.html" class="my-image">
<img src="https://homepages.cae.wisc.edu/~ece533/images/monarch.png" alt="Project description" class="image">
</a>
<div id="tail" class="description">
Butterflies are insects in the macrolepidopteran clade Rhopalocera from the order Lepidoptera, which also includes moths. Adult butterflies have large, often brightly coloured wings, and conspicuous, fluttering flight.
</div>
</div>
I hope this helps i recenty made one myselff for my website a few days ago
No info cursor:
.info:hover .tooltip {
color: red;
visibility: visible;
opacity: 1;
transition: opacity 1s
}
.tooltip {
visibility: hidden;
opacity: 0;
transition: opacity 1s
}
}
.tootip:hover {
visibility: visible
}
<span class="info"><img src="https://google.com/favicon.ico">Hover Me</img> <span class="tooltip">Welcome</span></a></span>
With info cursor:
.info:hover .tooltip {
color: red;
visibility: visible;
opacity: 1;
transition: opacity 1s
}
.tooltip {
visibility: hidden;
opacity: 0;
transition: opacity 1s
}
}
.tootip:hover {
visibility: visible
}
.info {
cursor: help
}
<span class="info"><img src="https://google.com/favicon.ico">Hover Me</img> <span class="tooltip">Welcome</span></a></span>

How to vertically center text from image overlay

I'm trying to recreate the google image row layout because I can't find any library that can help me. It doesn't matter how many images you add or the size, the row will auto adjust. I'm pretty close except for the vertical alignment of the "Hover text". I'd like to have it in the center of the image. I read this could be done by line-height but this does not work properly when you use a longer piece of text.
Here is my code jsFiddle
<div class="image-row">
<a href="#1" class="wrapper">
<span class="text">Hover text</span>
<img src="https://source.unsplash.com/random/768x960" width="768" height="960"/>
</a>
<a href="#2" class="wrapper">
<span class="text">Hover text</span>
<img src="https://source.unsplash.com/random/1280x851" width="1280" height="851"/>
</a>
<a href="#2" class="wrapper">
<span class="text">Hover text</span>
<img src="https://source.unsplash.com/random/1600x1600" width="1600" height="1600"/>
</a>
</div>
function picRow(selector) {
masterArray = [];
// create each lineArray and push it to masterArray
$(selector).each(function () {
// get "selector" css px value for margin-bottom
// - parse out a floating point number
// - and divide by the outer width to get a decimal percentage
margin = (parseFloat($(this).css("margin-bottom"), 10)) / ($(this).outerWidth());
marginRight = margin * 100 + "%";
// subtract subtract the total child margin from the total width to find the usable width
usableWidth = (1 - ((($(this).find("img").length) - 1) * margin));
// for each child img of "selector" - add a width/height as value in the ratios array
ratios = [];
$(this).find("img").each(function () {
ratios.push(($(this).attr('width')) / ($(this).attr('height')));
});
// sum all the ratios for later divison
ratioSum = 0;
$.each(ratios, function () {
ratioSum += parseFloat(this) || 0;
});
lineArray = [];
$.each(ratios, function (i) {
obj = {
// divide each item in the ratios array by the total array
// as set that as the css width in percentage
width: ((ratios[i] / ratioSum) * usableWidth) * 100 + "%",
height: ((ratios[i] / ratioSum) * usableWidth) * 100 + "%",
// set the margin-right equal to the parent margin-bottom
marginRight: marginRight
};
lineArray.push(obj);
});
lineArray[lineArray.length - 1].marginRight = "0%";
// alert(lineArray[lineArray.length - 1].marginRight);
masterArray.push(lineArray);
});
$(selector).each(function (i) {
$(this).find("img").each(function (x) {
$(this).css({
"width": masterArray[i][x].width,
"margin-right": masterArray[i][x].marginRight
});
});
$(this).find(".text").each(function (x) {
var imgHeight = $(this).parent().find("img").height();
//console.log(imgHeight)
$(this).css({
"width": masterArray[i][x].width,
"height": imgHeight,
"margin-right": masterArray[i][x].marginRight
});
});
});
}
$(document).ready(function () {
picRow(".image-row");
});
$( window ).resize(function() {
picRow(".image-row");
});
html, body {
height: 100%;
}
.image-row {
width: 100%;
margin: 1% 0;
}
.image-row img {
width: 100%;
height: auto;
display: block;
font-size: 0;
float: left;
}
.image-row::after {
content: "";
display: table;
clear: both;
}
*{
box-sizing: border-box;
}
.wrapper {
position: relative;
padding: 0;
/*width:100px;*/
display:block;
}
.text {
position: absolute;
top: 50%;
/*line-height: 441px;*/
color:#9CBDBE;
font-weight:bold;
font-size:100%;
background-color:#fff;
width: 100px;
text-align: center;
padding: 1%;
z-index: 10;
opacity: 0;
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
}
.text:hover {
opacity:0.8;
}
img {
z-index:1;
}
People tell me this is possible without jQuery and just using CSS but then I lose all the responsiveness..
You can add this following code to your .text class in your css :
.text {
position: absolute;
top: 50%;
line-height: 150px;
color:#9CBDBE;
font-weight:bold;
font-size:17px;
background-color:#fff;
width: 100px;
text-align: center;
padding: 1%;
z-index: 10;
opacity: 0;
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
}
Here is the jsfiddle https://jsfiddle.net/jfgnta38/1/
Also, if i may, you should learn flexbox which is a really useful "tool" to put your element where you want.
Please find below code
<div class="image-row">
<a href="#1" class="wrapper">
<img src="https://source.unsplash.com/random/768x960" width="768" height="960"/>
<div class="overlay">
<div class="text">Hover</div>
</div>
</a>
<a href="#2" class="wrapper">
<img src="https://source.unsplash.com/random/1280x851" width="1280" height="851"/>
<div class="overlay">
<div class="text">Hover</div>
</div>
</a>
<a href="#2" class="wrapper">
<img src="https://source.unsplash.com/random/1600x1600" width="1600" height="1600"/>
<div class="overlay">
<div class="text">Hover</div>
</div>
</a>
</div>
--- Jquery
function picRow(selector) {
masterArray = [];
// create each lineArray and push it to masterArray
$(selector).each(function () {
// get "selector" css px value for margin-bottom
// - parse out a floating point number
// - and divide by the outer width to get a decimal percentage
margin = (parseFloat($(this).css("margin-bottom"), 10)) / ($(this).outerWidth());
marginRight = margin * 100 + "%";
// subtract subtract the total child margin from the total width to find the usable width
usableWidth = (1 - ((($(this).find("img").length) - 1) * margin));
// for each child img of "selector" - add a width/height as value in the ratios array
ratios = [];
$(this).find("img").each(function () {
ratios.push(($(this).attr('width')) / ($(this).attr('height')));
});
// sum all the ratios for later divison
ratioSum = 0;
$.each(ratios, function () {
ratioSum += parseFloat(this) || 0;
});
lineArray = [];
$.each(ratios, function (i) {
obj = {
// divide each item in the ratios array by the total array
// as set that as the css width in percentage
width: ((ratios[i] / ratioSum) * usableWidth) * 100 + "%",
height: ((ratios[i] / ratioSum) * usableWidth) * 100 + "%",
// set the margin-right equal to the parent margin-bottom
marginRight: marginRight
};
lineArray.push(obj);
});
lineArray[lineArray.length - 1].marginRight = "0%";
// alert(lineArray[lineArray.length - 1].marginRight);
masterArray.push(lineArray);
});
$(selector).each(function (i) {
$(this).find("img").each(function (x) {
$(this).parent().css({
"width": masterArray[i][x].width,
"margin-right": masterArray[i][x].marginRight
});
});
});
}
$(document).ready(function () {
picRow(".image-row");
});
$( window ).resize(function() {
picRow(".image-row");
});
-- CSS
html, body {
height: 100%;
}
.image-row {
width: 100%;
margin: 1% 0;
}
.image-row img {
width: 100%;
height: auto;
display: block;
font-size: 0;
float: left;
}
.image-row::after {
content: "";
display: table;
clear: both;
}
*{
box-sizing: border-box;
}
.wrapper {
position: relative;
padding: 0;
display: block;
font-size: 0;
float: left;
}
.overlay {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
height: 100%;
width: 100%;
opacity: 0;
transition: .5s ease;
background-color: #fff;
}
.wrapper:hover .overlay {
opacity: 0.8;
}
.text {
color: #000;
font-size: 20px;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
text-align: center;
}
img {
z-index:1;
}
** Please replace above code then it will achieve your requirement easily.
You can try using bootstrap https://getbootstrap.com/docs/4.0/layout/grid/ to get it done

progress bar is not working

i am trying to made progress bar but its can working plz solve it .
i am using if else for increasing the width but it's not working
var x = document.getElementById("p_bar");
for(var i = 0; i < 100; i++) {
var wid;
wid=1;
if(wid == 800)
break;
else
wid+=8;
x.style.width=wid+"px";
}
document.body.style.background = "#"+((1<<24)*Math.random()|0).toString(16);
#cont {
width: 800px;
height: 30px;
background-color: cornsilk;
position: relative;
}
#p_bar {
width: 8px;
height: 30px;
background-color: red;
position: absolute;
}
<div id="cont">
<div id="p_bar"></div>
</div>
<p id="write"></p>
var x=document.getElementById("p_bar");
var wid = 1;
var it = setInterval(function(){
if(wid <= 800){
wid+=8;
x.style.width=wid+"px";
}else{
clearInterval(it);
}
}, 1000);
document.body.style.background = "#"+((1<<24)*Math.random()|0).toString(16);
#cont{
width: 800px;
height: 30px;
background-color: cornsilk;
position: relative;
}
#p_bar{
width: 8px;
height: 30px;
background-color: red;
position: absolute;
}
<div id="cont">
<div id="p_bar"></div></div>
<p id="write"></p>
If you want to see moving progress bar, You should use setInterval().
If you use just for, you can't see any animation.
Because, computer's calculating is so fast, so you can see only the result of for
I wrote it again using functions, try this shubham:
var x = document.getElementById('p_bar');
var container = document.getElementById('cont');
var write = document.getElementById('write');
var containerWidth = container.offsetWidth;
var currentWidth = x.offsetWidth;
var compeleteProgress = function (step, every) {
currentWidth = Math.min(currentWidth + step, containerWidth);
write.innerHTML = Math.floor((currentWidth / containerWidth) * 100) + '%' // Priniting percentage
x.style.width = currentWidth + 'px'
if (currentWidth < containerWidth) setTimeout(function () {
compeleteProgress(step, every)
}, every)
}
compeleteProgress(8, 300) // When you call this function, everything starts
document.body.style.background = "#"+((1<<24)*Math.random()|0).toString(16);
#cont{
width: 800px;
height: 30px;
background-color: cornsilk;
position: relative;
}
#p_bar{
width: 8px;
height: 30px;
background-color: red;
position: absolute;
}
<div id="cont">
<div id="p_bar"></div>
</div>
<p id="write"></p>
I am not sure what behavior you really expects. The Bar size is usually changed according to any application events (in my example by timeouts). I hope this helps:
document.body.style.background = "#"+((1<<24)*Math.random()|0).toString(16);
var setBarWidthInPercent = function(barId, value){
var bar=document.getElementById(barId);
bar.style.width = value+"%";
}
setTimeout(function(){
setBarWidthInPercent("p_bar",10)
},500)
setTimeout(function(){
setBarWidthInPercent("p_bar",50)
},1500)
setTimeout(function(){
setBarWidthInPercent("p_bar",100)
},3000)
#cont{
width: 800px;
height: 30px;
background-color: cornsilk;
position: relative;
}
#p_bar{
width: 8px;
height: 30px;
background-color: red;
position: absolute;
-webkit-transition: width 1s ease-in-out;
-moz-transition: width 1s ease-in-out;
-o-transition: width 1s ease-in-out;
transition: width 1s ease-in-out;
}
<div id="cont">
<div id="p_bar"></div></div>
<p id="write"></p>

Fixing the right button of a vanilla Javascript carousel

Against all reason, I'm trying to create a vanilla JavaScript carousel.
I am having two problems:
1. The images move left at widths of -680px as they should but when I tried to create the same function for the right button, the left value goes to 1370px making the picture off the screen.
2. I would like for it to slide left rather jump left (same for right), I managed to get it to do this but it doesn't work on the first slide, only from the second slide.
Here is the HTML code just for the carousel:
<div id = "container">
<div id = "carousel">
<div class = "slide"><img class = "slideImage" class = "active" src = "sithCover.png"></div>
<div class = "slide"><img class = "slideImage" src = "darthVader.png"></div>
<div class = "slide"><img class = "slideImage" src = "darthSidious.png"></div>
<div class = "slide"><img class = "slideImage" src = "kyloRen.png"></div>
</div>
</div>
<div id = "left" class = "button"></div>
<div id = "right" class = "button"></div>
Here is the CSS code:
#container {
position: absolute;
top: 200px;
left: 100px;
width: 680px;
height: 360px;
white-space: nowrap;
overflow:hidden;
}
#carousel {
position: absolute;
width: 2740px;
height: 360px;
white-space: nowrap;
overflow: hidden;
transition: left 300ms linear;
}
.slide {
display: inline-block;
height: 360px;
width: 680px;
padding: 0;
margin: 0;
transition: left 300ms linear;
}
.slideImage {
position:relative;
height: 360px;
width: 680px;
float: left;
}
.button {
position: absolute;
top: 340px;
height: 60px;
width: 60px;
border-bottom: 12px solid red;
}
#left {
left: 115px;
border-left: 12px solid red;
transform: rotate(45deg);
}
#right {
left: 693px;
border-right: 12px solid red;
transform: rotate(-45deg);
}
Here is the JavaScript:
var carousel = document.querySelector('#carousel');
var firstVal = 0;
document.querySelector('#left').addEventListener("click", moveLeft);
function moveLeft (){
firstVal +=685;
carousel.style.left = "-"+firstVal+"px";
};
document.querySelector('#right').addEventListener("click", moveRight);
function moveRight() {
firstVal +=685;
carousel.style.left = "+"+firstVal+"px";
};
Here is a JSFiddle so that you can see what I mean:
"https://jsfiddle.net/way81/8to1kkyj/"
I appreciate your time in reading my question and any help would be much appreciated.
Ofcourse it goes from -685px on left click and then to +1370pxthe next right click; You are always adding 685 to your firstVal variable.
firstVal = 0
//firstVal is worth 0
moveLeft()
//firstVal is now worth 685
moveRight()
//firstVal is now worth 1370.
The problem is that when you apply the firstVal to your CSS thing in the javascript, you create a string to get your negative value (where you apply the "-" sign infront of firstVal)
Instead, write them like this
function moveLeft (){
firstVal -=685; //note we now subtract, the "-" should appear when the number becomes negative
carousel.style.left = firstVal + "px";
};
function moveRight() {
firstVal +=685;
carousel.style.left = firstVal + "px";
};
var left = document.getElementById("left");
left.addEventListener("click", moveLeft, false);
var right = document.getElementById("right");
right.addEventListener("click", moveRight, false);
var carousel = document.getElementById("carousel");
var images = document.getElementsByTagName("img");
var position = 0;
var interval = 685;
var minPos = ("-" + interval) * images.length;
var maxPos = interval * images.length;
//slide image to the left side <--
function moveRight() {
if (position > (minPos + interval)) {
position -= interval;
carousel.style.left = position + "px";
}
if (position === (minPos + interval)) {
right.style.display = "none";
}
left.style.display = "block";
}
//slide image to the right side -->
function moveLeft() {
if (position < (maxPos - interval) && position < 0) {
position += interval;
carousel.style.left = position + "px";
}
if (position === 0) {
left.style.display = "none";
}
right.style.display = "block";
}
#container {
position: absolute;
top: 200px;
left: 100px;
width: 680px;
height: 360px;
white-space: nowrap;
overflow: hidden;
}
#carousel {
position: absolute;
width: 2740px;
height: 360px;
white-space: nowrap;
overflow: hidden;
transition: left 300ms linear;
}
.slide {
display: inline-block;
height: 360px;
width: 680px;
padding: 0;
margin: 0;
transition: left 300ms linear;
}
.slideImage {
position: relative;
height: 360px;
width: 680px;
float: left;
}
.button {
position: absolute;
top: 340px;
height: 60px;
width: 60px;
border-bottom: 12px solid red;
}
#left {
left: 115px;
border-left: 12px solid red;
transform: rotate(45deg);
display: none;
}
#right {
left: 693px;
border-right: 12px solid red;
transform: rotate(-45deg);
}
<div id="container">
<div id="carousel">
<div class="slide">
<img class="slideImage" class="active" src="sithCover.png" alt="slide1">
</div>
<div class="slide">
<img class="slideImage" src="darthVader.png" alt="slide2">
</div>
<div class="slide">
<img class="slideImage" src="darthSidious.png" alt="slide3">
</div>
<div class="slide">
<img class="slideImage" src="kyloRen.png" alt="slide4">
</div>
</div>
</div>
<div id="left" class="button"></div>
<div id="right" class="button"></div>

Move to specific div based on button click

I was trying to move the divs (here it's question number) based on the prev and next button. So that the selected question is always visible on screen.
Here is the demo : http://jsfiddle.net/arunslb123/trxe4n3u/12/
Screen :
click and question number and click prev or next button to understand my issue.
My code :
$("#next")
.click(function () {
$(".c.current-question")
.each(function () {
var divIdx = $(this)
.attr('id');
var scrollTo = $('#' + divIdx)
.position()
.left;
$("#scrollquestion")
.animate({
'scrollLeft': scrollTo
}, 800);
});
});
$("#prev")
.click(function () {
$(".c.current-question")
.each(function () {
var divIdx = $(this)
.attr('id');
var scrollTo = $('#' + divIdx)
.position()
.left;
$("#scrollquestion")
.animate({
'scrollLeft': -scrollTo
}, 800);
});
});
Using scrollLeft is a bit tricky. I did a small redo of your use-case based on positioning and then moving it based on left of the container. The tricky part is to reliably calculate the negative position when scrolled to the extreme right. Also, need to take into account the widths and margins.
Check the below snippet:
var $wrap = $("#numWrap"), $strip = $("#strip"),
$leftArrow = $(".wrapper > .arrows").first(),
wrapWidth = $wrap.width() + $leftArrow.width(),
margin = 10;
fill(20); select($(".numberItem").first());
$strip.on("click", ".numberItem", function() { select($(this)); });
function select($elem) {
$(".numberItem").removeClass("selected");
$elem.addClass("visited").addClass("selected");
focus($elem[0]);
}
function focus(elem) {
var stripPos = $strip.position(),
numPos = $(elem).offset(),
elemWidth = $(elem).width() + margin,
numRight = numPos.left + elemWidth;
if (numRight > wrapWidth) {
$strip.css({"left": stripPos.left - elemWidth});
}
if (numPos.left < (margin + $leftArrow.width())) {
$strip.css({"left": stripPos.left + elemWidth});
}
}
$(".wrapper").on("click", "a.arrow", function() {
var stripPos = $strip.position();
if (this.id == "lft") {
$strip.css({"left": stripPos.left + (wrapWidth / 2)});
} else {
$strip.css({"left": stripPos.left - (wrapWidth / 2)});
}
});
$(".controls").on("click", "a.arrow", function() {
var $sel = $(".selected"), numPos, $sel, elemWidth;
$elem = $sel.length > 0 ? $sel.first() : $(".numberItem").first();
if (this.id == "lft") {
$sel = $elem.prev().length > 0 ? $elem.prev() : $elem;
select($sel);
} else {
$sel = $elem.next().length > 0 ? $elem.next() : $elem;
select($sel);
}
numPos = $sel.offset(); elemWidth = $sel.width() + margin;
numRight = numPos.left + elemWidth;
if (numPos.left > wrapWidth) {
$strip.css({"left": -($sel.text()) * $sel.width() });
}
if (numRight < 0) {
$strip.css({"left": +($sel.text()) * $sel.width() });
}
});
function fill(num){
for (var i = 1; i <= num; i++) {
var $d = $("<a href='#' class='numberItem'>" + i + "</a>");
$strip.append($d);
}
}
* { box-sizing: border-box; padding: 0; margin: 0; font-family: sans-serif; }
div.wrapper {
background-color: #ddd; width: 100vw; height: 64px;
clear: both; overflow: hidden; margin-top: 16px;
}
div.arrows {
float: left; width: 10%; min-width: 24px; height: 64px; line-height: 64px;
text-align: center; vertical-align: middle; overflow: hidden;
}
div.numWrap {
float: left; height: 64px; line-height: 64px;
width: 80%; vertical-align: middle;
overflow: hidden; position: relative;
}
div.strip {
position: absolute; left: 0px;
width: auto; white-space: nowrap;
transition: left 1s;
}
a.numberItem {
display: inline-block; text-align: center; margin: 0px 8px;
background-color: #fff; border-radius: 50%; width: 48px; height: 48px;
font-size: 1.2em; line-height: 48px; text-decoration: none;
}
a.numberItem.visited { background-color: #fff; color: #000; border: 2px solid #01aebc; }
a.numberItem.selected { background-color: #01aebc; color: #fff; }
div.controls { clear: both; }
div.controls > div.arrows { width: auto; margin: 0 12px; }
a, a:focus, a:active, a:link, a:visited {
display: inline-block;
text-decoration: none; font-weight: 600;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<div class="arrows">
<a id="lft" class="arrow" href="#">〈</a>
</div>
<div id="numWrap" class="numWrap">
<div id="strip" class="strip"></div>
</div>
<div class="arrows">
<a id="rgt" class="arrow" href="#">〉</a>
</div>
</div>
<div class="controls">
<div class="arrows">
<a id="lft" class="arrow" href="#">〈 Previous</a>
</div>
<div class="arrows">
<a id="rgt" class="arrow" href="#">Next 〉</a>
</div>
<div>
Explanation:
Using absolute positioning on the number container, which is nested to get 100% width.
Markup:
<div class="wrapper">
<div class="arrows"><a id="lft" class="arrow" href="#">〈</a></div>
<div id="numWrap" class="numWrap">
<div id="strip" class="strip"></div> <!-- nesting here -->
</div>
<div class="arrows"><a id="rgt" class="arrow" href="#">〉</a></div>
</div>
CSS:
div.wrapper {
background-color: #ddd; width: 100vw; height: 64px;
clear: both; overflow: hidden; margin-top: 16px;
}
div.arrows {
float: left; width: 10%; min-width: 24px; height: 64px; line-height: 64px;
text-align: center; vertical-align: middle; overflow: hidden;
}
div.numWrap {
float: left; height: 64px; line-height: 64px;
width: 80%; vertical-align: middle;
overflow: hidden; position: relative; /* relatively positioned */
}
div.strip {
position: absolute; left: 0px; /* absolutely positioned */
width: auto; white-space: nowrap;
transition: left 1s; /* instead of jquery animate */
}
With this structure, we can now use left to control the scrolling.
For partially obscured numbers, try to gently focus-in (nudge into view) a number which is partially obscured. This can be done by checking the position relative to parent and adding the width/margin to it and also accounting for width of the left arrow (it might peep thru).
Javascript:
function focus(elem) {
var stripPos = $strip.position(),
numPos = $(elem).offset(),
elemWidth = $(elem).width() + margin,
numRight = numPos.left + elemWidth;
// if it is towards right side, nudge it back inside
if (numRight > wrapWidth) {
$strip.css({"left": stripPos.left - elemWidth});
}
// if it is towards left side, nudge it back inside
if (numPos.left < (margin + $leftArrow.width())) {
$strip.css({"left": stripPos.left + elemWidth});
}
}
Once the user has scrolled the list too far and then tries to click on previous / next buttons to select a question, then we need to move the entire container upto the selected number. We can easily do this by multiplying the question number with element width and then changing the left in positive (if towards right) or in negative (if towards left).
Javascript:
// if left of element is more than the width of parent
if (numPos.left > wrapWidth) {
$strip.css({"left": -($sel.text()) * $sel.width() });
}
// if right of element is less than 0 i.e. starting position
if (numRight < 0) {
$strip.css({"left": +($sel.text()) * $sel.width() });
}
Here is a fiddle to play with: http://jsfiddle.net/abhitalks/aw166qhx/
You will need to further adapt it to your use-case, but you get the idea.

Categories