JavaScript stop scrolling horizontally at the last div - javascript

Hi I am trying to create a carousel like object where you are able to click left and right to view between previous and next images using only HTML, CSS and JavaScript. Here is the code:
const container = document.querySelector(".container");
const lefty = document.querySelector(".lefty");
let translate = 0;
lefty.addEventListener("click", function() {
translate += 200;
container.style.transform = "translateX(" + translate + "px" + ")";
});
const righty = document.querySelector(".righty");
righty.addEventListener("click", function() {
translate -= 200;
container.style.transform = "translateX(" + translate + "px" + ")";
});
.outer {
overflow-x: hidden;
overflow-y: hidden;
}
.container {
display: flex;
transition: transform .4s ease-in;
}
.inner {
flex: 0 0 25%;
height: 100px;
margin: 10px;
}
.paddle {
position: absolute;
top: 50px;
bottom: 0;
width: 30px;
height: 20px;
}
.lefty {
left: 0;
z-index: 1;
}
.righty {
right: 0;
z-index: 1;
}
<button class="lefty paddle" id="left-button"></button>
<div class="outer" id="content">
<div class="container">
<div class="inner" style="background:red"></div>
<div class="inner" style="background:green"></div>
<div class="inner" style="background:blue"></div>
<div class="inner" style="background:yellow"></div>
<div class="inner" style="background:orange"></div>
</div>
</div>
<button class="righty paddle" id="right-button"></button>
The only issue I am having with this is that you can scroll way past the final div color block. Is it possible so that you can't scroll past the first and final div?
CodePen https://codepen.io/laurentkosc1990/pen/eYNXaxG

There are many approaches to solving this. In this example I define a max and min value that you can transform and check against that to stop the carousel. Either this can be fixed values or they can be dynamic to let you add and remove inner modules freely.
static
let minX = -400
let maxX = 0
dynamic
//number of inner classes times length, negate the visible classes
let minX = (inn.length * -200) + 600
const container = document.querySelector(".container");
const inn = document.getElementsByClassName('inner');
const lefty = document.querySelector(".lefty");
let translate = 0;
//let minX = -400
//number of inner classes times length, negate the visible classes
let minX = (inn.length * -200) + 600
let maxX = 0
lefty.addEventListener("click", function() {
if(translate >= maxX){
return;
}
translate += 200;
container.style.transform = "translateX(" + translate + "px" + ")";
});
const righty = document.querySelector(".righty");
righty.addEventListener("click", function() {
if(translate <= minX){
return;
}
translate -= 200;
container.style.transform = "translateX(" + translate + "px" + ")";
});
.outer {
overflow-x: hidden;
overflow-y: hidden;
}
.container {
display: flex;
transition: transform .4s ease-in;
}
.inner {
flex: 0 0 25%;
height: 100px;
margin:10px;
}
.paddle {
position: absolute;
top: 50px;
bottom: 0;
width: 30px;
height:20px;
}
.lefty {
left: 0;
z-index:1;
}
.righty{
right: 0;
z-index:1;
}
<button class="lefty paddle" id="left-button"></button>
<div class="outer" id="content">
<div class="container">
<div class="inner" style="background:red"></div>
<div class="inner" style="background:green"></div>
<div class="inner" style="background:blue"></div>
<div class="inner" style="background:yellow"></div>
<div class="inner" style="background:orange"></div>
</div>
</div>
<button class="righty paddle" id="right-button"></button>

maybe this will work for you
const container = document.querySelector(".container");
const visibleWidth = container.offsetWidth; // visible width of container
const fullWidth = container.scrollWidth; //width of container incliding hidden part
const innerDivWidth = document.querySelector(".inner").offsetWidth+20;// margin 10px from both sides
const lefty = document.querySelector(".lefty");
let translate = 0;
lefty.addEventListener("click", function() {
if(translate<0){
translate += innerDivWidth;
container.style.transform = "translateX(" + translate + "px" + ")";
}
});
const righty = document.querySelector(".righty");
righty.addEventListener("click", function() {
//here is my calculation, look carefully, you will get it
if((translate + fullWidth) > visibleWidth){
translate -= innerDivWidth;
container.style.transform = "translateX(" + translate + "px" + ")";
}
});
// btw translation rate should be according to inner div's width
// otherwise last div will not show properly
.outer {
overflow-x: hidden;
overflow-y: hidden;
}
.container {
display: flex;
transition: transform .4s ease-in;
}
.inner {
flex: 0 0 25%;
height: 100px;
margin: 10px;
}
.paddle {
position: absolute;
top: 50px;
bottom: 0;
width: 30px;
height: 20px;
}
.lefty {
left: 0;
z-index: 1;
}
.righty {
right: 0;
z-index: 1;
}
<button class="lefty paddle" id="left-button"></button>
<div class="outer" id="content">
<div class="container">
<div class="inner" style="background:red"></div>
<div class="inner" style="background:green"></div>
<div class="inner" style="background:blue"></div>
<div class="inner" style="background:yellow"></div>
<div class="inner" style="background:orange"></div>
</div>
</div>
<button class="righty paddle" id="right-button"></button>

Related

How can I move tooltip on top of the mouse pointer?

let screenLog = document.querySelector('#screen-log');
document.addEventListener('mousemove', logKey);
var imgHgt = document.getElementById('box');
function logKey(e) {
var d = document.getElementById('TextHidden');
d.style.position = "absolute";
d.style.left = e.clientX +'px';
d.style.top = e.clientY +'px';
screenLog.innerHTML = `${e.clientX}, ${e.clientY}` + "<br>Image Height = " + imgHgt.offsetHeight + "<br>Image Width = " + imgHgt.offsetWidth;
}
#box { width: 40%; display: block; position: absolute; overflow: hidden; }
.image { display: block; width: 100%; z-index: 1; }
#TextHidden { display: none; color: red; font-size; 20px; z-index: 10; } #box:hover #TextHidden { display: block; }
#screen-log { z-index: 11; }
<div id="box">
<img src="https://res.cloudinary.com/vaqar/image/upload/v1499826226/DSC_0361_y3mv4r.jpg" class="image"></p> </img>
<div id="TextHidden">Hovering<p id="screen-log"></p></div>
</div>
I am trying to move comments on top of the the mouse pointer, but having no success.
Change your left and top position pixels like,
d.style.left = (e.clientX - 50) +'px';
d.style.top = (e.clientY - 100) +'px';
And the snippet as follows,
let screenLog = document.querySelector('#screen-log');
document.addEventListener('mousemove', logKey);
var imgHgt = document.getElementById('box');
function logKey(e) {
var d = document.getElementById('TextHidden');
d.style.position = "absolute";
d.style.left = (e.clientX - 50) +'px';
d.style.top = (e.clientY - 100) +'px';
screenLog.innerHTML = `${e.clientX}, ${e.clientY}` + "<br>Image Height = " + imgHgt.offsetHeight + "<br>Image Width = " + imgHgt.offsetWidth;
}
#box { width: 40%; display: block; position: absolute; overflow: hidden; }
.image { display: block; width: 100%; z-index: 1; }
#TextHidden { display: none; color: red; font-size; 20px; z-index: 10; } #box:hover #TextHidden { display: block; }
#screen-log { z-index: 11; }
<div id="box">
<img src="https://res.cloudinary.com/vaqar/image/upload/v1499826226/DSC_0361_y3mv4r.jpg" class="image"></p> </img>
<div id="TextHidden">Hovering<p id="screen-log"></p></div>
</div>
Your approach is working in principle, but you don't see the moving text because it is currently hidden. Note that I commented out the overflow: hidden and display: none properties in your stylesheet.
let screenLog = document.querySelector('#screen-log');
document.addEventListener('mousemove', logKey);
var imgHgt = document.getElementById('box');
function logKey(e) {
var d = document.getElementById('TextHidden');
d.style.position = "absolute";
d.style.left = e.clientX + 'px';
d.style.top = e.clientY + 'px';
screenLog.innerHTML = `${e.clientX}, ${e.clientY}` + "<br>Image Height = " + imgHgt.offsetHeight + "<br>Image Width = " + imgHgt.offsetWidth;
}
#box {
width: 40%;
display: block;
position: absolute;
#overflow: hidden;
}
.image {
display: block;
width: 100%;
z-index: 1;
}
#TextHidden {
#display: none;
color: red;
font-size: 20px;
z-index: 10;
}
#box:hover #TextHidden {
display: block;
}
#screen-log {
z-index: 11;
}
<div id="box">
<div id="TextHidden">
<p id="screen-log"></p>
</div>
</div>

JavaScript style.height of sister div on mouseover

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%';
}

How to set an exact background position based on element's position?

What I am trying to achieve: using the same image, set an elements background-position with jQuery, so they overlaps closest parents background-image. I somehow figured, that $element.property().left needs to be multiplied by something close to 2 (still don't really understand why it's so), but I cannot see any math pattern in it.
If anybody could tell me what exactly comes into an equation, it'd be great help. I imagine there is padding and margin of an element and all the elements up the DOM tree involved, but after lot of combinations I still cannot get there.
It might seem that the best way to get desired effect is just to set background: transparent;, but it is not the case; I need it for further usage of filter CSS property on the element's background image.
There are inline styles in HTML added for testing; also, I created jsfiddle.
$.fn.filteredImg= function() {
var $this = $(this)
$this.each(function(index, card) {
var $card = $(card);
var img = $card.data("img");
var $parent = $card.parentsUntil("[data-img='" + img + "']").last().parent();
var $effect = $card.children(".filtered-effect");
var pos = $card.position();
$parent.css({
backgroundImage: "url(" + img + ")",
backgroundRepeat: "no-repeat"
});
$effect.css({
backgroundImage: "url(" + img + ")",
backgroundPosition: -2 * Math.ceil(pos.left) + "px " + -Math.round(pos.top) + "px"
});
})
}
$(".card-filtered-img").filteredImg();
.card-filtered-img {
width: 80%;
min-height: 500px;
margin-left: 77px;
margin-top: 17px;
position: relative;
}
.card-filtered-img > * {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.card-filtered-img .filtered-effect {
z-index: 99;
}
.card-filtered-img .card-content {
background: rgba(34, 34, 34, 0.35);
z-index: 100;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-img="http://www.planwallpaper.com/static/images/colorful-wallpaper2.jpg">
<div class="container" style="margin-top:30px">
<div class="row" style="padding:30px">
<div class="col">
<div class="card-filtered-img" data-img="http://www.planwallpaper.com/static/images/colorful-wallpaper2.jpg">
<div class="filtered-effect"></div>
<div class="card-content"></div>
</div>
<div class="card-filtered-img" data-img="http://www.planwallpaper.com/static/images/colorful-wallpaper2.jpg">
<div class="filtered-effect"></div>
<div class="card-content"></div>
</div>
</div>
</div>
</div>
Here is the solution base on offset instead of position (and I simplified the code):
$.fn.filteredImg= function() {
var $this = $(this);
$this.each(function(index, card) {
var $card = $(card);
var $effect = $card.children(".filtered-effect");
var $parent = $(card).parents(".parent").first();
var img = $parent.data("img");
var cardPos = $card.offset();
$parent.css({
backgroundImage: "url(" + img + ")",
backgroundRepeat: "no-repeat"
});
$effect.css({
backgroundImage: "url(" + img + ")",
backgroundPosition: -cardPos.left + "px " + -cardPos.top + "px"
});
})
}
$(".card-filtered-img").filteredImg();
.card-filtered-img {
width: 80%;
min-height: 500px;
margin-left: 77px;
margin-top: 17px;
position: relative;
}
.card-filtered-img > * {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.card-filtered-img .filtered-effect {
z-index: 99;
}
.card-filtered-img .card-content {
background: rgba(34, 34, 34, 0.35);
z-index: 100;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent" data-img="http://www.planwallpaper.com/static/images/colorful-wallpaper2.jpg">
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="card-filtered-img">
<div class="filtered-effect"></div>
<div class="card-content"></div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="card-filtered-img">
<div class="filtered-effect"></div>
<div class="card-content"></div>
</div>
</div>
</div>
</div>
Since/If you use the full viewport, you can use viewport units to position and size the inner card's and drop the script all together.
This also scales when you resize and will give you a performance boost since you don't need a script to watch for resize and redraw.
Note, for this demo I ran this without bootstrap, as I didn't want to add compensations for its media query's etc.
Updated fiddle
html, body {
margin: 0;
overflow-x: hidden;
}
.outer {
height: 1080px;
width: 100vw;
}
.card-acrylic {
top: 20px;
width: 80vw;
margin-left: 10vw;
min-height: 500px;
position: relative;
background-position: left -10vw top -20px;
}
.card-acrylic + .card-acrylic {
top: 40px;
background-position: left -10vw top -540px;
}
.card-acrylic > * {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.card-acrylic .acrylic-effect {
z-index: 99;
}
.card-acrylic .card-content {
background: rgba(34, 34, 34, 0.35);
z-index: 100;
}
<div class="outer" style="background-image: url(http://www.planwallpaper.com/static/images/colorful-wallpaper2.jpg)">
<div class="card-acrylic" style="background-image: url(http://www.planwallpaper.com/static/images/colorful-wallpaper2.jpg)">
<div class="acrylic-effect"></div>
<div class="card-content"></div>
</div>
<div class="card-acrylic" style="background-image: url(http://www.planwallpaper.com/static/images/colorful-wallpaper2.jpg)">
<div class="acrylic-effect"></div>
<div class="card-content"></div>
</div>
</div>

How can I mirror this animation?

I have a panel on the left side of my screen that flips out when activated. As you move your mouse around, it slightly alters the rotateY transform for a nice interactive effect. I want to mirror this on the right side of the screen, but every adjustment I make just causes the panel to freak out when you move the mouse.
What adjustments need to be made to the second jquery function to mirror the effect? I tried a lot of things including the current code which is replacing x = x + 15 with x = 360 - (x + 15). It's close, but still not right.
$(document).on('mousemove','#viewport1 .menu',function( event ) {
var x = Math.round(event.pageX / $(this).width() * 10);
x = x + 15;
$(this).css('transform','rotateY(' + x + 'deg)');
});
$(document).on('mousemove','#viewport2 .menu',function( event ) {
var x = Math.round(event.pageX / $(this).width() * 10);
x = 360 - (x + 15); //this is almost but not quite right...
$(this).css('transform','rotateY(' + x + 'deg)');
});
.viewport {
perspective: 1000px;
position: absolute;
top: 0; bottom:0; width: 30%;
padding: 5px;
}
.menu {
text-align: center;
width: 100%;
border: 1px solid black;
display: inline-block;
height: 100%;
}
#viewport1 {
left: 0;
}
#viewport1 .menu {
perspective-origin: left;
transform-origin: left;
transform: rotateY(15deg);
}
#viewport2 {
text-align: right;
right: 0;
}
#viewport2 .menu {
perspective-origin: right;
transform-origin: right;
transform: rotateY(345deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="viewport1" class="viewport">
<div class="menu">HOVER ME!</div>
</div>
<div id="viewport2" class="viewport">
<div class="menu">HOVER ME!</div>
</div>
You are using event.pageX, which is the position of the mouse pointer, relative to the left edge of the document, to calculate the rotation of the <div>. You need to substract the left offset: $(this).offset().left. After that you change x+15 to x-15 and you get the mirrored effect.
$(document).on('mousemove','#viewport1 .menu',function( event ) {
var x = Math.round(event.pageX / $(this).width() * 10);
x = x + 15;
$(this).css('transform','rotateY(' + x + 'deg)');
});
$(document).on('mousemove','#viewport2 .menu',function( event ) {
var x = Math.round((event.pageX - $(this).offset().left) / $(this).width() * 10);
x = x - 15;
$(this).css('transform','rotateY(' + x + 'deg)');
});
.viewport {
perspective: 1000px;
position: absolute;
top: 0; bottom:0; width: 30%;
padding: 5px;
}
.menu {
width: 100%;
border: 1px solid black;
display: inline-block;
height: 100%;
}
#viewport1 {
left: 0;
}
#viewport1 .menu {
perspective-origin: left;
transform-origin: left;
transform: rotateY(15deg);
}
#viewport2 {
text-align: right;
right: 0;
}
#viewport2 .menu {
perspective-origin: right;
transform-origin: right;
transform: rotateY(345deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="viewport1" class="viewport">
<div class="menu"></div>
</div>
<div id="viewport2" class="viewport">
<div class="menu"></div>
</div>

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>

Categories