I want to write my own jQuery slider, which shows a small part of the next and previous image (for example 20px).
To achieve this, I have created a simple image slider, using float: left; to arrange all the images in one row inside a overflow: hidden div.
All my images got a fixed width of 200px. Because of this I calculate the margins of each image with the following sass:
img {
float: left;
display: block;
margin: 0 calc((100vw - 200px) / 4 - 20px);
&:first-child {
margin-left: calc((100vw - 200px) / 2);
}
&:last-child {
margin-right: calc((100vw - 200px) / 2);
}
}
This works great and positions every image as it should be.
While trying to animate the slider using transform: translateX(); I am totally lost calculating the amount of pixels (in vw/%/px) I need to translateX the $('#slider').
How can I calculate the translateX value to slide to each image centered?
$(document).ready(function(){
document.getElementById('slider').ondragstart = function() { return false; };
var slider = $('#slider'),
images = slider.find('img'),
imageCount = images.length,
currentIndex = 0;
slider.width( imageCount * 100 + "vw");
var slideLeft = function () {
if ( currentIndex >= imageCount - 1 ) {
console.log("Last image reached");
return;
}
currentIndex += 1;
console.log("Slide left");
slider.css("transform", "translateX(" + currentIndex * -10 + "vw)");
}
var slideRight = function () {
if ( currentIndex === 0 ) {
console.log("First image reached");
return;
}
currentIndex -= 1;
console.log("Slide right");
slider.css("transform", "translateX(" + currentIndex * -10 + "vw)");
}
$('#right').on('click', function(){
slideLeft();
});
$('#left').on('click', function(){
slideRight();
});
});
html, body {
margin: 0;
padding: 0;
}
#slider-container {
overflow: hidden;
height: 300px;
background: rgba(0, 0, 0, 0.05);
margin: 5vw 0;
width: 100vw;
}
#slider {
height: 300px;
transition: transform .3s ease-in-out;
transform: translateX(0);
}
#slider img {
float: left;
display: block;
margin: 0 calc((100vw - 200px) / 4 - 20px);
}
#slider img:first-child {
margin-left: calc((100vw - 200px) / 2);
}
#slider img:last-child {
margin-right: calc((100vw - 200px) / 2);
}
#controls {
position: relative;
width: 100vw;
display: block;
height: calc(10vw + 100px);
}
#controls .arrow {
display: block;
width: 100px;
top: 5vw;
background: lightgray;
height: 100px;
left: 5vw;
position: absolute;
font-size: 100px;
line-height: 80px;
font-weight: bold;
text-align: center;
cursor: pointer;
}
#controls .arrow:hover {
background: lightblue;
}
#controls #right {
left: auto;
right: 5vw;
}
p {
margin: 0 5vw 5vw;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="slider-container">
<div id="slider">
<img src="https://unsplash.it/200/300?image=1077" alt="img-1">
<img src="https://unsplash.it/200/300?image=1076" alt="img-2">
<img src="https://unsplash.it/200/300?image=1072" alt="img-3">
<img src="https://unsplash.it/200/300?image=1063" alt="img-4">
<img src="https://unsplash.it/200/300?image=1061" alt="img-5">
</div>
</div>
<div id="controls">
<div id="left" class="arrow">‹</div>
<div id="right" class="arrow">›</div>
</div>
<p>Currently every scroll click scrolls a random amount to the left or right. This needs to be fixed, so that every image is centered after the slide.</p>
I had made few updates in your script.
try with this script
$(document).ready(function(){
document.getElementById('slider').ondragstart = function() { return false; };
var slider = $('#slider'),
images = slider.find('img'),
imageCount = images.length,
currentIndex = 0;
slider.width( imageCount * 100 + "vw");
var $this = $("#slider-container");
var offset = $this.offset();
var width = $this.width();
var centerX = (offset.left + width / 2 ) + (images.width() / 2) - 40;
var slideLeft = function () {
if ( currentIndex >= imageCount - 1 ) {
console.log("Last image reached");
return;
}
currentIndex += 1;
console.log("Slide left");
slider.css("transform", "translateX(-" + (currentIndex * centerX) + "px)");
}
var slideRight = function () {
if ( currentIndex === 0 ) {
console.log("First image reached");
return;
}
currentIndex -= 1;
console.log("Slide right");
slider.css("transform", "translateX(-" + (currentIndex * centerX) + "px)");
}
$('#right').on('click', function(){
slideLeft();
});
$('#left').on('click', function(){
slideRight();
});
});
check this fiddle : jsFiddle
Related
I'm trying to get to grips with javascript, and have followed a tutorial for a simple image slider. I'm trying to add to it and have the background fade to different colours as the slides move. I've managed to figure it out with the right and left arrows (not sure on best practise), but I can't seem to get it right when selecting the indicators. Can anyone advise on a solution?
Thanks in advance.
const left = document.querySelector('.left');
const right = document.querySelector('.right');
const slider = document.querySelector('.carousel__slider');
const indicatorParent = document.querySelector('.carousel__controls ol');
const indicators = document.querySelectorAll('.carousel__controls li');
index = 0;
var background = 1;
function indicatorBg(val){
var background = val;
changeBg();
}
indicators.forEach((indicator, i) => {
indicator.addEventListener('click', () => {
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicator.classList.add('selected');
slider.style.transform = 'translateX(' + (i) * -25 + '%)';
index = i;
});
});
left.addEventListener('click', function() {
index = (index > 0) ? index -1 : 0;
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicatorParent.children[index].classList.add('selected');
slider.style.transform = 'translateX(' + (index) * -25 + '%)';
if (background <= 1) {
return false;
} else {
background--;
}
changeBg();
});
right.addEventListener('click', function() {
index = (index < 4 - 1) ? index+1 : 3;
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicatorParent.children[index].classList.add('selected');
slider.style.transform = 'translateX(' + (index) * -25 + '%)';
if (background >= 4) {
return false;
} else {
background++;
}
changeBg();
});
function changeBg (){
if (background == 1) {
document.getElementById("carousel__track").className = 'slide-1';
} else if (background == 2) {
document.getElementById("carousel__track").className = 'slide-2';
} else if (background == 3) {
document.getElementById("carousel__track").className = 'slide-3';
} else if (background == 4) {
document.getElementById("carousel__track").className = 'slide-4';
}
}
window.onload = changeBg;
.carousel {
height: 80vh;
width: 100%;
margin: 0 auto;
}
#carousel__track {
height: 100%;
position: relative;
overflow: hidden;
}
.background {
background: red;
}
.carousel__slider {
height: 100%;
display: flex;
width: 400%;
transition: all 0.3s;
}
.carousel__slider div {
flex-basis: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.carousel__controls .carousel__arrow {
position: absolute;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
z-index: 8888
}
.carousel__controls .carousel__arrow i {
font-size: 2.6rem;
}
.carousel__arrow.left {
left: 1em;
}
.carousel__arrow.right {
right: 1em;
}
.carousel__controls ol {
position: absolute;
bottom: 15%;
left: 50%;
transform: translateX(-50%);
list-style: none;
display: flex;
margin: 0;
padding: 0;
}
.carousel__controls ol li {
width: 14px;
height: 14px;
border-radius: 50px;
margin: .5em;
padding: 0;
background: white;
transform: scale(.6);
cursor: pointer;
}
.carousel__controls ol li.selected {
background: black;
transform: scale(1);
transition: all .2s;
transition-delay: .3s;
}
.slide-1 {
background: pink;
transition: all 0.4s;
}
.slide-2 {
background: coral;
transition: all 0.4s;
}
.slide-3 {
background: green;
transition: all 0.4s;
}
.slide-4 {
background: orange;
transition: all 0.4s;
}
<section class="carousel">
<div id="carousel__track">
<div class="carousel__slider">
<div>Slide 1</div>
<div>Slide 2</div>
<div>Slide 3</div>
<div>Slide 4</div>
</div>
<div id="left" class="carousel__controls"><span class="carousel__arrow left"><</span> <span id="right" class="carousel__arrow right">></span>
<ol>
<li value="1" onclick="indicatorBg(this.value)" class="selected"></li>
<li value="2" onclick="indicatorBg(this.value)"></li>
<li value="3" onclick="indicatorBg(this.value)"></li>
<li value="4" onclick="indicatorBg(this.value)"></li>
</ol>
</div>
</div>
</section>
You forgot to change the background inside the click event handler of the indicators.
indicators.forEach((indicator, i) => {
indicator.addEventListener('click', () => {
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicator.classList.add('selected');
slider.style.transform = 'translateX(' + (i) * -25 + '%)';
index = i;
background = index + 1;
changeBg();
});
});
As far as best practice goes, I typically use class names for CSS and IDs for JavaScript. Personally, I wouldn't recommend you worry about best practices at this stage, but instead, focus on getting the code working and understanding what's going on line-by-line.
There is a lot of solutions, but the simplest solution that I advice is to use odd and even numbers to style the divs in the carousel (meaning that eg. first is green second is orange third is green and so on...
.carousel__slider div:nth-child(2n) /*Selects even numbered elements*/
.carousel__slider div:nth-child(2n+1) /*Selects odd numbered elements*/
Check out the snippet
const left = document.querySelector('.left');
const right = document.querySelector('.right');
const slider = document.querySelector('.carousel__slider');
const indicatorParent = document.querySelector('.carousel__controls ol');
const indicators = document.querySelectorAll('.carousel__controls li');
index = 0;
//var background = 1;
//function indicatorBg(val){
// var background = val;
// changeBg();
//}
indicators.forEach((indicator, i) => {
indicator.addEventListener('click', () => {
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicator.classList.add('selected');
slider.style.transform = 'translateX(' + (i) * -25 + '%)';
index = i;
});
});
left.addEventListener('click', function() {
index = (index > 0) ? index -1 : 0;
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicatorParent.children[index].classList.add('selected');
slider.style.transform = 'translateX(' + (index) * -25 + '%)';
// if (background <= 1) {
// return false;
// } else {
// background--;
// }
// changeBg();
});
right.addEventListener('click', function() {
index = (index < 4 - 1) ? index+1 : 3;
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicatorParent.children[index].classList.add('selected');
slider.style.transform = 'translateX(' + (index) * -25 + '%)';
// if (background >= 4) {
// return false;
// } else {
// background++;
// }
// changeBg();
});
//function changeBg (){
// if (background == 1) {
// document.getElementById("carousel__track").className = 'slide-1';
// } else if (background == 2) {
// document.getElementById("carousel__track").className = 'slide-2';
// } else if (background == 3) {
// document.getElementById("carousel__track").className = 'slide-3';
// } else if (background == 4) {
// document.getElementById("carousel__track").className = 'slide-4';
// }
//}
//window.onload = changeBg;
.carousel {
height: 80vh;
width: 100%;
margin: 0 auto;
}
#carousel__track {
height: 100%;
position: relative;
overflow: hidden;
}
.background {
background: red;
}
.carousel__slider {
height: 100%;
display: flex;
width: 400%;
transition: all 0.3s;
}
.carousel__slider div {
flex-basis: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.carousel__controls .carousel__arrow {
position: absolute;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
z-index: 8888
}
.carousel__controls .carousel__arrow i {
font-size: 2.6rem;
}
.carousel__arrow.left {
left: 1em;
}
.carousel__arrow.right {
right: 1em;
}
.carousel__controls ol {
position: absolute;
bottom: 15%;
left: 50%;
transform: translateX(-50%);
list-style: none;
display: flex;
margin: 0;
padding: 0;
}
.carousel__controls ol li {
width: 14px;
height: 14px;
border-radius: 50px;
margin: .5em;
padding: 0;
background: white;
transform: scale(.6);
cursor: pointer;
}
.carousel__controls ol li.selected {
background: black;
transform: scale(1);
transition: all .2s;
transition-delay: .3s;
}
/*.slide-1 {
background: pink;
transition: all 0.4s;
}
.slide-2 {
background: coral;
transition: all 0.4s;
}
.slide-3 {
background: green;
transition: all 0.4s;
}
.slide-4 {
background: orange;
transition: all 0.4s;
}*/
.carousel__slider div:nth-child(2n) {
background-color:orange;
}
.carousel__slider div:nth-child(2n+1) {
background-color:green;
}
<section class="carousel">
<div id="carousel__track">
<div class="carousel__slider">
<div>Slide 1</div>
<div>Slide 2</div>
<div>Slide 3</div>
<div>Slide 4</div>
</div>
<div id="left" class="carousel__controls"><span class="carousel__arrow left"><</span> <span id="right" class="carousel__arrow right">></span>
<ol>
<li value="1" class="selected"></li>
<li value="2" ></li>
<li value="3" ></li>
<li value="4" ></li>
</ol>
</div>
</div>
</section>
I'm trying to make a carousel and I'm kind of stuck on stopping it from scrolling when the last slide is reached.
So far I have this JS code
var width = 130; //width of one slide
var position = 0;
var carousel = document.getElementById('carousel');
var list = carousel.querySelector('ul');
carousel.querySelector('.prev').onclick = function() {
position = Math.min(position + width, 0)
console.log(position)
list.style.marginLeft = position + 'px';
};
carousel.querySelector('.next').onclick = function() {
position = position - width
console.log(position)
list.style.marginLeft = position + 'px';
};
So I'm taking width of one slide and based on that change margin of container.
When scrolling left I solved the problem by setting position to 0 with Math.min.This way when I 'm on the first slide it doesn`t scroll left.
But I'm not sure how to do the same when on my last slide.
Link to working exmaple
Here's what you want , I just added a test comparing the position and the size of all the sliders.
var width = 130;
var carousel = document.getElementById('carousel');
var list = carousel.querySelector('ul');
var position = 0;
var carouselwidth = document.getElementsByClassName('gallery')[0].offsetWidth;
//number of silder
var nbslider = list.getElementsByTagName("li").length;
//number of silder per page
var nbsliderp = carouselwidth / width
console.log(nbsliderp);
//size of silders per page
var szsliderp = nbsliderp * width;
carousel.querySelector('.prev').onclick = function() {
position = Math.min(position + width, 0)
console.log(position)
list.style.marginLeft = position + 'px';
};
carousel.querySelector('.next').onclick = function() {
//console.log((position - szsliderp) + (nbslider * width))
if (((position - szsliderp) + (nbslider * width)) > 0) {
position = position - width
//console.log(position)
list.style.marginLeft = position + 'px';
}
};
body {
padding: 10px;
}
.carousel {
position: relative;
width: 398px;
padding: 10px 40px;
background: #eee;
}
.carousel img {
width: 130px;
height: 130px;
margin-right: 2px;
display: block;
}
.arrow {
position: absolute;
top: 60px;
padding: 0;
font-size: 24px;
line-height: 24px;
color: #444;
display: block;
}
.arrow:focus {
outline: none;
}
.arrow:hover {
background: #ccc;
cursor: pointer;
}
.prev {
left: 7px;
}
.next {
right: 7px;
}
.gallery {
width: 390px;
overflow: hidden;
}
.gallery ul {
height: 130px;
width: 9999px;
margin: 0;
padding: 0;
list-style: none;
transition: margin-left 250ms;
font-size: 0;
}
.gallery li {
display: inline-block;
}
<div id="carousel" class="carousel">
<button class="arrow prev"></button>
<div class="gallery">
<ul class="images">
<li><img src="https://cdn.houseplans.com/product/o2d2ui14afb1sov3cnslpummre/w1024.jpg?v=15"></li>
<li><img src="https://cdn.houseplans.com/product/o2d2ui14afb1sov3cnslpummre/w1024.jpg?v=15"></li>
<li><img src="https://cdn.houseplans.com/product/o2d2ui14afb1sov3cnslpummre/w1024.jpg?v=15"></li>
<li><img src="https://cdn.houseplans.com/product/o2d2ui14afb1sov3cnslpummre/w1024.jpg?v=15"></li>
<li><img src="https://cdn.houseplans.com/product/o2d2ui14afb1sov3cnslpummre/w1024.jpg?v=15"></li>
<li><img src="https://cdn.houseplans.com/product/o2d2ui14afb1sov3cnslpummre/w1024.jpg?v=15"></li>
</ul>
</div>
<button class="arrow next">></button>
</div>
I'm using a jQuery slideshow plugin but it doesn't have an option for autoplay. Currently, the only way to trigger the slides is by clicking the left and right arrows.
Anyone have any solutions? I did some research but couldn't find anyone who came up with a solution yet and the original developer doesn't appear to be coding anymore.
Below is the slider I'm using on codepen.
(function() {
var carouselContent, carouselIndex, carouselLength, firstClone, firstItem, isAnimating, itemWidth, lastClone, lastItem;
carouselContent = $(".carousel__content");
carouselIndex = 0;
carouselLength = carouselContent.children().length;
isAnimating = false;
itemWidth = 100 / carouselLength;
firstItem = $(carouselContent.children()[0]);
lastItem = $(carouselContent.children()[carouselLength - 1]);
firstClone = null;
lastClone = null;
carouselContent.css("width", carouselLength * 100 + "%");
carouselContent.transition({
x: (carouselIndex * -itemWidth) + "%"
}, 0);
$.each(carouselContent.children(), function() {
return $(this).css("width", itemWidth + "%");
});
$(".nav--left").on("click", function() {
if (isAnimating) {
return;
}
isAnimating = true;
carouselIndex--;
if (carouselIndex === -1) {
lastItem.prependTo(carouselContent);
carouselContent.transition({
x: ((carouselIndex + 2) * -itemWidth) + "%"
}, 0);
return carouselContent.transition({
x: ((carouselIndex + 1) * -itemWidth) + "%"
}, 1000, "easeInOutExpo", function() {
carouselIndex = carouselLength - 1;
lastItem.appendTo(carouselContent);
carouselContent.transition({
x: (carouselIndex * -itemWidth) + "%"
}, 0);
return isAnimating = false;
});
} else {
return carouselContent.transition({
x: (carouselIndex * -itemWidth) + "%"
}, 1000, "easeInOutExpo", function() {
return isAnimating = false;
});
}
});
$(".nav--right").on("click", function() {
if (isAnimating) {
return;
}
isAnimating = true;
carouselIndex++;
return carouselContent.transition({
x: (carouselIndex * -itemWidth) + "%"
}, 1000, "easeInOutExpo", function() {
isAnimating = false;
if (firstClone) {
carouselIndex = 0;
carouselContent.transition({
x: (carouselIndex * -itemWidth) + "%"
}, 0);
firstClone.remove();
firstClone = null;
carouselLength = carouselContent.children().length;
itemWidth = 100 / carouselLength;
carouselContent.css("width", carouselLength * 100 + "%");
$.each(carouselContent.children(), function() {
return $(this).css("width", itemWidth + "%");
});
return;
}
if (carouselIndex === carouselLength - 1) {
carouselLength++;
itemWidth = 100 / carouselLength;
firstClone = firstItem.clone();
firstClone.addClass("clone");
firstClone.appendTo(carouselContent);
carouselContent.css("width", carouselLength * 100 + "%");
$.each(carouselContent.children(), function() {
return $(this).css("width", itemWidth + "%");
});
return carouselContent.transition({
x: (carouselIndex * -itemWidth) + "%"
}, 0);
}
});
});
}).call(this);
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
body, html {
font-family: "europa-1","europa-2", sans-serif;
overflow: hidden;
}
.wrapper {
max-width: 940px;
width: 100%;
position: relative;
overflow: hidden;
margin: 0 auto;
}
/**
* Use this wrapper only for demo purposes
* So you can show the items outside the wrapper
*/
.wrapper--demo {
overflow: visible;
}
.wrapper--demo:after, .wrapper--demo:before {
content: "";
position: absolute;
width: 800px;
height: 100%;
top: 0;
left: 100%;
background: rgba(255, 255, 255, 0.8);
z-index: 2;
}
.wrapper--demo:before {
left: -800px;
}
.carousel {
width: 100%;
position: relative;
}
.carousel .carousel__content {
width: auto;
position: relative;
overflow: hidden;
-webkit-backface-visibility: hidden;
-webkit-transition: translate3d(0, 0, 0);
}
.carousel .carousel__content .item {
display: block;
float: left;
width: 100%;
position: relative;
}
.carousel .carousel__content .item .title {
position: absolute;
top: 50%;
left: 0;
margin: -33px 0 0 0;
padding: 0;
font-size: 3rem;
width: 100%;
text-align: center;
letter-spacing: .3rem;
color: #FFF;
}
.carousel .carousel__content .item .title--sub {
margin-top: 20px;
font-size: 1.2em;
opacity: .5;
}
.carousel .carousel__content .item img {
width: 100%;
max-width: 100%;
display: block;
}
.carousel .carousel__nav {
position: absolute;
width: 100%;
top: 50%;
margin-top: -17px;
left: 0;
z-index: 1;
}
.carousel .carousel__nav .nav {
position: absolute;
top: 0;
color: #000;
background: #FFF;
padding: 8px 12px;
font-weight: bold;
text-decoration: none;
font-size: .8rem;
transition: padding .25s ease;
}
.carousel .carousel__nav .nav:hover {
padding: 8px 20px;
}
.carousel .carousel__nav .nav--left {
border-radius: 0px 3px 3px 0px;
}
.carousel .carousel__nav .nav--right {
right: 0;
border-radius: 3px 0px 0px 3px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/jquery.transit/0.9.9/jquery.transit.min.js"></script>
<div class="wrapper wrapper--demo">
<div class="carousel">
<div class="carousel__content">
<div class="item">
<p class="title">First</p>
<img src="http://placehold.it/1800x850/70AD96/FFF&text= " alt="">
</div>
<div class="item">
<p class="title">Second</p>
<img src="http://placehold.it/1800x850/EA4E23/FFF&text= " alt="">
</div>
<div class="item">
<p class="title">Third</p>
<img src="http://placehold.it/1800x850/9BA452/FFF&text= " alt="">
</div>
<div class="item">
<p class="title">Fourth</p>
<img src="http://placehold.it/1800x850/472D38/FFF&text= " alt="">
</div>
<div class="item">
<p class="title">Fifth</p>
<img src="http://placehold.it/1800x850/F77C85/FFF&text= " alt="">
</div>
<div class="item">
<p class="title">Sixth</p>
<p class="title title--sub">Last Item</p>
<img src="http://placehold.it/1800x850/00FFAE/FFF&text= " alt="">
</div>
</div>
<div class="carousel__nav">
Previous
Next
</div>
</div>
</div>
Use jQuery .click() to mimic user click on the corresponding DOM element which is $(".nav--left").click() & $(".nav--right").click() in your case.
Use setInterval to achieve the desired "autplay effect".
This should do it quick and dirty; just append it to your existing script. Have fun with this working Forked PEN (there is also a link to an advanced one at the bottom).
JavaScript:
var autoSlide = function( sDirection ) {
sDirection === 'left' || sDirection = 'right';
$( '.nav--' + sDirection ).click(); // ".nav--left" or ".nav--right"
};
setInterval( function() {
autoSlide(); // with default direction: 'right'
// autoSlide( 'left' ) // slide left
}, 1000 ); // every 1000 milliseconds
CoffeeScript:
autoSlide = ( sDirection ) ->
sDirection == 'left' || sDirection = 'right'
$( ".nav--#{sDirection}" ).click()
setInterval(
-> autoSlide() # with default direction: 'right'
# autoSlide( 'left' ) # slide left
1000 # every second
)
I only posted whats new instead of repeating your answers snippet! If you have any questions about customization or general functionality feel free to leave a comment.
PEN with advanced control capabilities.
shortened version (reduced to the very essential):
setInterval(function() { $('.nav--right').click() }, 1000 );
or for the other direction and as half as slow:
setInterval(function() { $('.nav--left').click() }, 2000 );
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>
I am using following link to show menus
http://codepen.io/anon/pen/dWdJbV
But I want to show them only in upper half circle. Even menu count changes it should use only upper half circle.
Js code
var items = document.querySelectorAll('.circle a');
for(var i = 0, l = items.length; i < l; i++) {
items[i].style.left = (50 - 35*Math.cos(-0.5 * Math.PI - 2*(2/l)*i*Math.PI)).toFixed(4) + "%";
items[i].style.top = (50 + 35*Math.sin(-0.5 * Math.PI - 2*(5/l)*i*Math.PI)).toFixed(4) + "%";
}
document.querySelector('.menu-button').onclick = function(e) {
e.preventDefault(); document.querySelector('.circle').classList.toggle('open');
}
I tried by changing values sin sin and cos but not getting required output
Here is the quick demo :
var isOn = false;
$('#menu-button').click(function() {
if(isOn) {
reset();
} else {
setPosition();
}
});
function setPosition() {
isOn = true;
var links = $('#menu-button a');
var radius = (links.length * links.width()) / 2;
var degree = Math.PI / links.length, angle = degree / 2;
links.each(function() {
var x = Math.round(radius * Math.cos(angle));
var y = Math.round(radius * Math.sin(angle));
$(this).css({
left: x + 'px',
top: -y + 'px'
});
angle += degree;
});
}
function reset() {
$('#menu-button a').css({
left: 0 + 'px',
top: 0 + 'px'
});
isOn = false;
}
body {
margin: 0;
background: #39D;
}
#menu-button:before {
position: absolute;
top: 0; left: 0;
width: 50px;
height: 50px;
background: #dde;
cursor: pointer;
text-align: center;
line-height: 50px;
color: #444;
border-radius:50%;
content:"\f0c9"; font: normal normal normal 14px/1 FontAwesome;
font-size:26px;
}
#menu-button {
position: absolute;
margin: auto;
top: 150px; left: 0; right: 0;
width: 50px;
height: 50px;
cursor: pointer;
text-align: center;
}
#menu-button > a {
position: absolute;
display: block;
width: 50px;
height: 50px;
-webkit-transition: top .5s, left .5s;
-moz-transition: top .5s, left .5s;
text-align: center;
text-decoration: none;
line-height: 50px;
color: #EBEAE8;
z-index: -1;
border-radius:50%;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- Demo by http://creative-punch.net -->
<div id="menu-button" class="entypo-menu">
</div>
I made this changes in you example for displaying items only in top part of circle:
var items = document.querySelectorAll('.circle a');
var angle = 0;
var step = (Math.PI) / items.length;
for(var i = 0, l = items.length; i < l; i++) {
items[i].style.left = (50 - 35*Math.cos(angle).toFixed(4)) + "%";
items[i].style.top = (50 + 35* (-Math.abs(Math.sin(angle)))).toFixed(4) + "%";
angle += step;
}
So you need only angles from 0 to 180 degrees. That's why i use (-Math.abs(Math.sin(angle)))