I have a content wrapper which has several sections in it, each section with a different id.
The sections can be accessed with a menu navigation which triggers a transform operation who uses translate3d to go between the sections, on horizontal, using an class named active to show which section should be displayed.
I placed two anchors with absolute position towards the content wrapper, something like arrows in a slideshow one on the left and one on the right.
Here is how the code looks
<div id="wrapper">
<a class="left-arrow" href="#"></a>
<a class="right-arrow" href="#"></a>
<header>
<nav id="main">
<a class="active" href="#!/one">one</a>
two
three
four
</nav>
</header>
<div class="content_wrapper" style="display: block; transform: translate3d(0px, 0px, 0px);">
<section id="one" class="active">content one</section>
<section id="two">content two</section>
<section id="three">content three</section>
<section id="four">content four</section>
</div>
</div>
the CSS
.left-arrow{ background: url('../img/left-arrow.png') left top no-repeat; height: 64px; width: 16px; display: block; position: absolute; top: 180px; left: 0; z-index: 10;}
.right-arrow{ background: url('../img/right-arrow.png') right top no-repeat; height: 64px; width: 16px; display: block; position: absolute; top: 180px; right: 0; z-index: 10;}
My problem is that I don't know how to hide the left arrow when the first section has the class active, and the right arrow when the last section has the class active. I tried with on and change but obviously I failed, I'm a rookie to jQuery element and event manipulation. Which selector should I use and which event? Can someone please give me some directions?
here is the jQuery part
(function (e) {
var r = !1;
e(window).on("hashchange", function (i) {
var s = e("section#" + document.location.hash.replace("#!/", ""));
if (!r && !s.hasClass("active")) {
r = !0;
e('nav#main a[href="' + document.location.hash + '"]').addClass("active").siblings().removeClass("active");
e("section.active").animate({
scrollTop: 0
}, 300);
e("section.active").children("footer").children("div.box").hide();
s.addClass("active").siblings().removeClass("active");
if (Modernizr.csstransitions && Modernizr.csstransforms3d) e("div.content_wrapper").transition({
transform: "translate3d(-" + 1e3 * s.index() + "px, 0, 0)"
}, {
duration: 800,
easing: "cubic-bezier(0.770, 0.000, 0.175, 1.000)"
}, function () {
r = !1
});
else {
e("div.content_wrapper").animate({
left: "-" + 1e3 * s.index() + "px"
}, {
duration: 800,
queue: !0
});
r = !1
}
}
});
})
Would add a class to all the sections so you can add or remove and not have to focus on specific ID being first/last
<section id="one" class="content active">content one</section>
function setArrowState(){
var $content=$('.content');
$('.left-arrow')[ $content.first().is('.active') ? 'hide' :'show' ]();
$('.right-arrow')[ $content.last().is('.active') ? 'hide' :'show' ]();
}
$(function(){
/* set arrows on page load*/
setArrowState();
});
EDIT: In haschange code shown, call setArrowState() on line after .addClass("active").siblings().removeClass("active");
You just need to have a variable know which is the element selected, so you can remove the class, and then set on the click event to add the class.
var menu1 = document.querySelector('#main1');
var menu2 = document.querySelector('#main2');
// etc
var selected = menu1;
var activeClass = function()
{
$(selected).removeClass('active');
$(this).addClass('active');
selected = this;
};
menu1.onclick = activeClass;
menu2.onclick = activeClass;
Related
I have a slide toggle that slides from right to left. I have some div elements and I want when clicking on them slideToggle only show and doesn't close on click again that div element. Only close when clicking to button in slideToggle
How can i do that? Here is my detailed code jsfiddle
I've transferred your jsfiddle to the StackOverflow code snippet below.
I've added an additional function slideOpen() to the code. The function checks to see if is_collapsed is true. If the condition is met, the function will open the slider.
The trick here is to set is_collapsed to false at the end of the function so it doesn't run the animation again and close the slider.
Now, the only way to close the slider is by clicking the open/close button that uses your slideToggle() function.
Please, run the snippet below to see this code in action. I've also added some comments to the slideOpen() function to explain what's happening.
var easing = 1;
var animation_speed = 200;
var slider_width;
var is_collapsed = true;
function slideToggle() {
is_collapsed = $('#btn').css("margin-right") == slider_width + "px" && !$('#btn').is(':animated');
var sign = (is_collapsed) ? '-' : '+';
if (!$('#btn').is(':animated')) {
if (easing) $('.willSlide').animate({
"margin-right": sign + '=' + slider_width
}, animation_speed);
else $('.willSlide').animate({
"margin-right": sign + '=' + slider_width
}, animation_speed);
}
(is_collapsed) ? $('.willSlide').removeClass('expanded'): $('.willSlide').addClass('expanded');
}
//function to open slide
function slideOpen() {
//if is_collapsed is true, animate div and open slider
if (is_collapsed) {
var sign = '+'
$('.willSlide').animate({
"margin-right": sign + '=' + slider_width
}, animation_speed);
//add expanded class to button when opened
$('.willSlide').addClass('expanded')
//set is_collapsed to false so it won't close slider on additional clicks
is_collapsed = false
}
}
$(document).ready(function() {
slider_width = $('#content').width(); //get width automaticly
$('#btn').click(slideToggle);
});
#content {
position: fixed;
height: 100%;
background: rgb(97, 97, 97);
width: 200px;
right: 0px;
margin-right: -200px;
}
#btn {
position: fixed;
width: 100px;
right: 0px;
background: rgb(117, 231, 117);
top: 100px;
border-radius: 5px 0px 0 5px;
color: #fff;
text-align: center;
padding: 40px 0;
cursor: pointer
}
.expandedTxt {
display: none
}
#btn.expanded .expandedTxt {
display: block
}
#btn.expanded .click {
display: none
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div onclick="slideOpen()">button1</div>
<div onclick="slideOpen()">button2</div>
<div class="willSlide" id='content'></div>
<div class="willSlide" id='btn'>
<span class="click">open</span>
<span class="expandedTxt">close</span>
</div>
I'd like to use https://github.com/lonekorean/mini-preview to create mouseover previews for parts of a website only.
I have no problems using anchors from the target website to have the script render a full website preview, scrolled to where an individual anchor is.
That's not what I'm after however.
I'd like the script to show only the content of the anchors' parent <p> or <div>.
On the site, the link target anchors are coded like this:
<div class="paragraph">
<p>
<a id="anchor_1"></a>
Foo bar baz.
</p>
</div>
So, I'd like the little preview box to show Foo bar baz. only.
I suspect the answer lies in this part of the script:
loadPreview: function() {
this.$el.find('.' + PREFIX + '-frame')
.attr('src', this.$el.attr('href'))
.on('load', function() {
// some sites don't set their background color
$(this).css('background-color', '#fff');
});
specifically, the .attr('src', this.$el.attr('href')) part.
I'm not sure though.
Does anyone know how I can do this?
Or can you recommend some other script that I can use to do this and makes things look as nice as this one?
I'm not a web dev, so please go easy on me.
Thanks
UPDATE (based on Swati's answer and corresponding comments):
For example, if my website includes this:
<body>
<p>
See internal
</p>
<p>
See external
</p>
<div class="paragraph">
<p>
<a id="anchor_on_my_site"></a>
Foo bar baz.
</p>
</div>
</body>
and the external website includes this:
<body>
<div class="paragraph">
<p>
<a id="external_anchor"></a>
Qux quux quuz.
</p>
</div>
</body>
I'd like See internal to display Foo bar baz. and See external to display Qux quux quuz.
Inside loadPreview function you can use closest('p').clone().children().remove().end().text() to get text from p tag where a has been hover then using this put that text to show inside your frame div i.e : .find('.' + PREFIX + '-frame').text(data_to_show) .
Demo Code :
(function($) {
var PREFIX = 'mini-preview';
$.fn.miniPreview = function(options) {
return this.each(function() {
var $this = $(this);
var miniPreview = $this.data(PREFIX);
if (miniPreview) {
miniPreview.destroy();
}
miniPreview = new MiniPreview($this, options);
miniPreview.generate();
$this.data(PREFIX, miniPreview);
});
};
var MiniPreview = function($el, options) {
this.$el = $el;
this.$el.addClass(PREFIX + '-anchor');
this.options = $.extend({}, this.defaultOptions, options);
this.counter = MiniPreview.prototype.sharedCounter++;
};
MiniPreview.prototype = {
sharedCounter: 0,
defaultOptions: {
width: 256,
height: 144,
scale: .25,
prefetch: 'parenthover'
},
generate: function() {
this.createElements();
this.setPrefetch();
},
createElements: function() {
var $wrapper = $('<div>', {
class: PREFIX + '-wrapper'
});
//no need to use iframe...use simple div
var $frame = $('<div>', {
class: PREFIX + '-frame'
});
var $cover = $('<div>', {
class: PREFIX + '-cover'
});
$wrapper.appendTo(this.$el).append($frame, $cover);
// sizing
$wrapper.css({
width: this.options.width + 'px',
height: this.options.height + 'px'
});
// scaling
var inversePercent = 100 / this.options.scale;
$frame.css({
width: inversePercent + '%',
height: inversePercent + '%',
transform: 'scale(' + this.options.scale + ')'
});
var fontSize = parseInt(this.$el.css('font-size').replace('px', ''), 10)
var top = (this.$el.height() + fontSize) / 2;
var left = (this.$el.width() - $wrapper.outerWidth()) / 2;
//add more style here ...if needed to outer div
$wrapper.css({
top: top + 'px',
left: left + 'px',
'font-size': '55px',
'color': 'blue'
});
},
setPrefetch: function() {
switch (this.options.prefetch) {
case 'pageload':
this.loadPreview();
break;
case 'parenthover':
this.$el.parent().one(this.getNamespacedEvent('mouseenter'),
this.loadPreview.bind(this));
break;
case 'none':
this.$el.one(this.getNamespacedEvent('mouseenter'),
this.loadPreview.bind(this));
break;
default:
throw 'Prefetch setting not recognized: ' + this.options.prefetch;
break;
}
},
loadPreview: function() {
//to get text from p tag
var data_to_show = this.$el.closest('p').clone().children().remove().end().text().trim()
//set new text inside div frame
this.$el.find('.' + PREFIX + '-frame').text(data_to_show)
//set bg color..
this.$el.find('.' + PREFIX + '-frame').css('background-color', '#fff');
},
getNamespacedEvent: function(event) {
return event + '.' + PREFIX + '_' + this.counter;
},
destroy: function() {
this.$el.removeClass(PREFIX + '-anchor');
this.$el.parent().off(this.getNamespacedEvent('mouseenter'));
this.$el.off(this.getNamespacedEvent('mouseenter'));
this.$el.find('.' + PREFIX + '-wrapper').remove();
}
};
})(jQuery);
$('a').miniPreview();
body {
height: 100%;
margin: 0;
padding: 0 10% 40px;
font-size: 2rem;
line-height: 1.5;
font-family: 'Roboto Slab', sans-serif;
text-align: justify;
color: #59513f;
background-color: #f5ead4;
}
a {
color: #537f7c;
}
.mini-preview-anchor {
display: inline-block;
position: relative;
white-space: nowrap;
}
.mini-preview-wrapper {
-moz-box-sizing: content-box;
box-sizing: content-box;
position: absolute;
overflow: hidden;
z-index: -1;
opacity: 0;
margin-top: -4px;
border: solid 1px #000;
box-shadow: 4px 4px 6px rgba(0, 0, 0, .3);
transition: z-index steps(1) .3s, opacity .3s, margin-top .3s;
}
.mini-preview-anchor:hover .mini-preview-wrapper {
z-index: 2;
opacity: 1;
margin-top: 6px;
transition: opacity .3s, margin-top .3s;
}
.mini-preview-cover {
background-color: rgba(0, 0, 0, 0);
/* IE fix */
}
.mini-preview-frame {
border: none;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<body>
<div class="paragraph">
<p>
<a id="anchor_1">See</a> This is text we are showing for first
</p>
<p>
<a id="anchor_2">See</a> This is text we are showing for second
</p>
</div>
</body>
</html>
Update 1 :
You can differentiate between external & internal link using some class i.e : simply check if the a tag which is hover has a particular class or not depending on this change your code to preview divs.
Updated Code :
if (this.$el.hasClass("internal")) {
//to get text from p tag
var data_to_show = this.$el.closest('p').siblings(".paragraph").clone().text().trim()
//set new text inside div frame
this.$el.find('.' + PREFIX + '-frame').text(data_to_show)
//set bg color..
this.$el.find('.' + PREFIX + '-frame').css('background-color', '#fff');
} else {
console.log("for external code ..")
}
In the following SSCCE, how can I animate the appearance of .items using show() and their disappearance using hide(), such that it looks like the item5, item6, item7, item8 have flown into the viewport?
That is, what I want is that when the .next-arrow is clicked, for example for the first time, the hiding of item1, item2, item3, item4, and the showing of item5, item6, item7, item8, is "transitioned" - just like new pages flow into the viewport in this website.
How can I do that?
$(document).ready(function() {
//alert('ready');//check
var numberOfItems = $('.item').length;
//alert('numberOfItems => ' + numberOfItems);//check
displayNextArrowOnCondition();
displayPreviousArrowOnCondition();
/**
*
**/
$('a.next-arrow').click(function(event) {
event.preventDefault();
var currentFirstItem = getCurrentFirstItem(); // Difference between var and no var SO: If you're in the global scope then there's no difference. If you're in a function then var will create a local variable, "no var" will look up the scope chain until it finds the variable or hits the global scope (at which point it will create it):
$('div.item' + currentFirstItem).hide(); //We don't need to have the condition of checking this element's existence because the next-arrow whose handler this method is, appears only if the numberOfItems is greater than the id of the item with the greatest id among the elements currently visible on the screen.
if (('div.item' + (currentFirstItem + 1)).length) { //SO: How can I check the existence of an element in jQuery?? In JavaScript, everything is truthy or falsy and for numbers, 0 means false, everything else true. So you could write: "if ($(selector).length)" - and you don't need that > 0 part.
$('div.item' + (currentFirstItem + 1)).hide();
}
if (('div.item' + (currentFirstItem + 2)).length) {
$('div.item' + (currentFirstItem + 2)).hide();
}
if (('div.item' + (currentFirstItem + 3)).length) {
$('div.item' + (currentFirstItem + 3)).hide();
}
hidePreviousArrow();
hideNextArrow();
displayPreviousArrowOnCondition();
displayNextArrowOnCondition();
});
/**
*
**/
$('a.previous-arrow').click(function(event) {
event.preventDefault();
var currentFirstItem = getCurrentFirstItem();
$('div.item' + (currentFirstItem - 1)).show();
if (('div.item' + (currentFirstItem - 2)).length) {
$('div.item' + (currentFirstItem - 2)).show();
}
if (('div.item' + (currentFirstItem - 3)).length) {
$('div.item' + (currentFirstItem - 3)).show();
}
if (('div.item' + (currentFirstItem - 4)).length) {
$('div.item' + (currentFirstItem - 4)).show();
}
hidePreviousArrow();
hideNextArrow();
displayPreviousArrowOnCondition();
displayNextArrowOnCondition();
});
/**
* DISPLAY NEXT ARROW WHEN
* 1. NUMBER OF ITEMS IS GREATER THAN THE id OF THE LAST ITEM DISPLAYED IN THE CURRENT VIEWPORT
**/
function displayNextArrowOnCondition() {
//alert('displayNextArrowOnCondition called');//check
//Iterate through items in OPPOSTIE order, and when found the first one which is not hidden by hide() or display:none, assign it to currentLastItem (because this is the first item in the viewport), and break out from the loop.
var currentLastItem = getCurrentLastItem();
//alert('currentLastItem -> ' + currentLastItem);//check
if (currentLastItem < numberOfItems) {
$('a.next-arrow').css('display', 'block');
$('.wrapper').mouseover(function() {
//$('a.next-arrow').css('visibility', 'visible');
});
$('.wrapper').mouseleave(function() {
//$('a.next-arrow').css('visibility', 'hidden');
});
}
}
/**
* DISPLAY PREVIOUS ARROW WHEN
* 1. THE id OF THE FIRST DISPLAYED ITEM IS GREATER THAN 4
**/
function displayPreviousArrowOnCondition() {
//Iterate through items in order, and when found the first one which is not hidden by hide() or display:none, assign it to currentFirstItem (because this is the first item in the viewport), and break out from the loop.
var currentFirstItem = getCurrentFirstItem();
if (currentFirstItem > 4) {
$('a.previous-arrow').css('display', 'block');
$('.wrapper').mouseover(function() {
$('a.previous-arrow').css('visibility', 'visible');
});
$('.wrapper').mouseleave(function() {
$('a.previous-arrow').css('visibility', 'hidden');
});
}
}
/**
* DISPLAY:NONE NEXT ARROW IF IT IS VISIBLE
**/
function hideNextArrow() {
//alert('hideNextArrow called');//check
if ($('a.next-arrow').css('display').toLowerCase() == 'block') { //The == operator will compare for equality after doing any necessary type conversions. The === operator will not do the conversion, so if two values are not the same type === will simply return false.| Just in case anyone was wondering in 2012: === is way faster than ==. jsperf.com/comparison-of-comparisons.
//alert('YES if ($(\'a.next-arrow\').attr(\'display\').toLowerCase() == \'block\'). SO I AM CHANGING IT TO none.');//check
$('a.next-arrow').css('display', 'none');
} //else { alert('NO if ($(\'a.next-arrow\').attr(\'display\').toLowerCase() == \'block\').'); } //check
}
/**
* DISPLAY:NONE PREVIOUS ARROW IF IT IS VISIBLE
**/
function hidePreviousArrow() {
//alert('hidePreviousArrow called');//check
//alert($('a.previous-arrow').css('display'));//check
if ($('a.previous-arrow').css('display') == 'block') {
//alert('YES if ($(\'a.previous-arrow\').attr(\'display\').toLowerCase() == \'block\'). SO I AM CHANGING IT TO none.');//check
$('a.previous-arrow').css('display', 'none');
} //else { alert('NO if ($(\'a.previous-arrow\').attr(\'display\').toLowerCase() == \'block\').'); } //check
}
/**
*
**/
function getCurrentFirstItem() {
for (i = 1; i <= numberOfItems; i++) {
if ($("#" + i).visible(true, true)) {
//alert('YES if ( $("#"+i).visible(true, true) )');//check
currentFirstItem = i;
break;
} //else { //alert('NO if ( $("#"+i).visible(true, true) )'); }//check
}
//alert('currentFirstItem -> ' + currentFirstItem);//check
return currentFirstItem;
}
/**
*
**/
function getCurrentLastItem() {
for (j = numberOfItems; j >= 1; j--) {
if ($("#" + j).visible(true, true)) {
//alert("YES if ( $(\"#\"+j).visible(true, true) ) ");//check
currentLastItem = j;
break;
} //else { //alert('NO if ( $("#"+j).visible(true, true) )'); } //check
}
//alert('currentLastItem -> ' + currentLastItem);//check
return currentLastItem;
}
});
html,
body,
body div,
span,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
abbr,
address,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
samp,
small,
strong,
sub,
sup,
var,
b,
i,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
figure,
footer,
header,
hgroup,
menu,
nav,
section,
time,
mark,
audio,
video,
details,
summary {
margin: 0px;
padding: 0px;
border: 0px none;
background: transparent none repeat scroll 0% 0%;
font-size: 100%;
vertical-align: baseline;
}
.wrapper {
position: relative;
white-space: nowrap;
overflow: hidden;
}
div.item {
/*position:absolute;*/
display: inline-block;
width: 25%;
height: 25vw;
}
.item1 {
left: 0%;
background-color: wheat;
}
.item2 {
left: 25%;
background-color: pink;
}
.item3 {
left: 50%;
background-color: beige;
}
.item4 {
left: 75%;
background-color: gainsboro;
}
.item5 {
left: 100%;
background-color: coral;
}
.item6 {
left: 125%;
background-color: crimson;
}
.item7 {
left: 150%;
background-color: aquamarine;
}
.item8 {
left: 175%;
background-color: darkgoldenrod;
}
.item9 {
left: 200%;
background-color: khaki;
}
.item10 {
left: 225%;
background-color: indianred;
}
.item11 {
left: 250%;
background-color: mediumspringgreen;
}
.previous-arrow,
.next-arrow {
width: 30px;
height: 50%;
top: 50%;
position: absolute;
opacity: 0.7;
color: white;
background-repeat: no-repeat;
margin-top: -30px;
display: none;
}
.previous-arrow {
background-image: url(a2.png);
left: 0px;
}
.next-arrow {
background-image: url(b2.png);
right: 0px;
}
.previous-arrow,
.next-arrow {
opacity: 1;
}
body {
background-color: black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://cdn.jsdelivr.net/jquery.visible/1.1.0/jquery.visible.min.js"></script>
<div class="wrapper">
<a class="previous-arrow" href="">></a>-->
<!--
-->
<div id="1" class="item item1 wheat">a.</div>
<!--
-->
<div id="2" class="item item2 pink">a.</div>
<!--
-->
<div id="3" class="item item3 beige">a.</div>
<!--
-->
<div id="4" class="item item4 gainsboro">a.</div>
<!--
-->
<div id="5" class="item item5 coral">a.</div>
<!--
-->
<div id="6" class="item item6 crimson">a.</div>
<!--
-->
<div id="7" class="item item7 darkgoldenrod">a.</div>
<!--
-->
<div id="8" class="item item8 aquamarine">a.</div>
<!--
-->
<div id="9" class="item item9 aquamarine">a.</div>
<!--
-->
<div id="10" class="item item10 aquamarine">a.</div>
<!--
-->
<div id="11" class="item item11 aquamarine">a.</div>
<!--
--><a class="next-arrow" href=""><</a>
</div>
If you want use show() and hide() only, you can use show('slow') and hide('slow'), etc. Other than that there are many ways and effects you can use.
Please follow this link to get to know how many ways were there to do this.
jQuery Effects
You can use css transitions or css animations. Animations like:
Define css class rules and assign class name to the elements you want to animate
.doFadeIn {
-webkit-animation:fadeInSlide forwards ease-in 150ms;
animation:fadeInSlide forwards ease-in 150ms;
}
.doFadeOut {
-webkit-animation:fadeOutSlideDown forwards ease-out 150ms;
animation:fadeOutSlideDown forwards ease-out 150ms;
}
Define keyframes for the animations
#keyframes fadeInSlide
{
0% { opactity:0; transform: translateX(-100px); }
100% { opactity:1; transform: translateX(0); }
}
When assigning doFadeIn to the class name of elements, they will:
Fade in - opacity:0 to 1 (0% visible to 100% visible)
Moves along the horizontal axis (X) 100px left of the elements original position to it's original position.
It will do this spanning the duration of 150 milli-seconds
<div id="my-widget1" class="my-widget"><div>
<div id="my-widget1" class="my-widget doFadeIn"><div>
You can pass a parameter for show() function like .show('slow') that will do the animation like fadeIn() function.
Check the documentation with examples
You can use .hide(), fadeOut(), show(), fadeIn()
Sample Codes
You can use .show() to Display the matched elements.
Sample code for when user type something on an input text show a list.
$("#search-guide").focusin(function () {
$("#list-user-guides").show();
});
You can use .hide() to Hide the matched elements.
Sample code for when user click somewhere else on the screen hide the list.
$("#search-guide").focusin(function () {
$("#list-user-guides").hide();
});
But i personally use .fadeIn() and fadeOut() because those two method come with a smooth animation.
You can check the official doc as mentioned above answers.
How can I make the carousel center the item I've clicked to the middle? I've looked everywhere for an answer but they're not straight answers... Can someone help me in this, please?
This is what I've done so far: http://jsfiddle.net/sp9Jv/
HTML:
<div id="wrapper">
<div id="carousel">
prev
next
<div class="viewport">
<ul>
<li>Un</li>
<li>Deux</li>
<li>Trois</li>
<li>Quatre</li>
<li>Cinq</li>
<li>Six</li>
<li>Sept</li>
<li>Huit</li>
</ul>
</div>
<!-- viewport -->
</div>
<!-- carousel -->
</div>
<!-- wrapper -->
JavaScript:
var carousel = $('#carousel'),
prev = carousel.find('.prev'),
next = carousel.find('.next'),
viewport = carousel.find('.viewport'),
item = viewport.find('li'),
itemWidth = item.outerWidth(true),
itemNum = item.length,
itemList = viewport.find('ul');
itemList.width(itemWidth * itemNum);
var moveCarousel = function(dir) {
itemList.animate({ left: '-=' + (itemWidth * dir) + 'px' }, 400);
};
//prev
prev.on('click', function(e) {
e.preventDefault();
moveCarousel(-1);
});
//next
next.on('click', function(e) {
e.preventDefault();
moveCarousel(1);
});
//carousel item
item.on('click', 'a', function(e) {
var self = $(this),
selfIndex = self.index(),
distance = itemList.width() / 2,
selfPos = self.position(),
selfPosLeft = selfPos.left,
viewportPosLeft = viewport.position().left;
e.preventDefault();
//move item to middle, but it doesn't work...
if (selfPosLeft > Math.floor(viewport.width())/3) {
itemList.animate({ left: '-' + Math.floor(viewport.width())/3 + 'px' }, 400);
}
if (selfPosLeft < Math.floor(viewport.width())/3) {
itemList.animate({ left: Math.floor(viewport.width())/3 + 'px' }, 400);
}
});
CSS:
#wrapper {
width: 500px;
margin: 20px auto;
}
#carousel {
position: relative;
}
.viewport {
width: 260px;
border: 1px solid #6e6e6e;
height: 80px;
overflow: hidden;
position: relative;
margin-left: 100px;
}
.prev, .next {
position: absolute;
}
.prev {
top: 20px;
left: 0;
}
.next {
top: 20px;
right: 0;
}
.viewport ul {
position: absolute;
}
.viewport li {
float: left;
margin-right: 10px;
}
.viewport li a {
display: block;
width: 80px;
height: 80px;
background: #ddd;
}
While you have prepared all the information needed about all items, you can calculate the value of the left based on the clicked item.
Here is my modification:
and I've bound the click action of carousel items with this function and passed the clicked item using the self keyword.
var itemClicked=function(item){
var itemIndex=$(item).index(),
newLeft=(itemIndex*itemWidth*-1)+Math.floor(($(viewport).width()/itemWidth)/2)*itemWidth;
$(itemList).animate({left:newLeft+"px"},400);
};
You can check it working on this url: http://jsfiddle.net/rUZHg/3/
I assume that this should work despite of the number of viewed elements while it calculates the padding between the left 0 and the left of the center element.
Alright, it's ugly, I hope it gives you some ideas.
I created a global currentItem that tracks what's in the center. Every time the carousel moves this is updated.
The very useful variable I found was selfPosLeft which told me what was being clicked. I should add that 90 was the multiple I got from clicking around. Must be linked to your CSS and I don't know how to find this number dynamically.
Please try it :) http://jsfiddle.net/sp9Jv/4/
Well, I'm picturing that when you have more than 3 items you can change the code to compute the difference between the current item and the selfPosLeft of the clicked one, I'll leave that to you :) Like this, seems to work. http://jsfiddle.net/sp9Jv/5/
I am adapting the Coverflow technique to work with a div. Following is the html:
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<style type="text/css" media="screen">
body,html {
margin: 0;
padding: 0;
background: #000;
height: 100%;
color: #eee;
font-family: Arial;
font-size: 10px;
}
div.magnifyme {
height: 80px;
padding: 80px;
position: absolute;
top: 0px;
left: 0px;
width: 2000px;
}
div.wrapper {
margin: 0px;
height: 470px;
/*border: 2px solid #999;*/
overflow: hidden;
padding-left: 40px;
right: 1px;
width: 824px;
position: relative;
}
div.container {position: relative; width: 854px; height: 480px; background: #000; margin: auto;}
div.nav {position: absolute; top: 10px; width: 20%; height: 10%; right: 1px; }
div.magnifyme div {
position: absolute;
width: 300px;
height: 280px;
float: left;
margin: 5px;
position: relative;
border: 2px solid #999;
background: #500;
}
</style>
<script type="text/javascript" src="jquery-1.3.2.js"></script>
<script type="text/javascript" src="ui.coverflow.js"></script>
<script type="text/javascript" src="ui.core.js"></script>
<script type="text/javascript">
$(function() {
$("div.magnifyme").coverflow();
$("#add").click(function() {
$(".magnifyme").append("<div id=\"div5\">hello world</div>");
$("div.magnifyme").coverflow();
});
});
</script>
</head>
<body>
<div class="container">
<div class="wrapper">
<div class="magnifyme">
<div id="div0">This is div 0</div>
<div id="div1">This is div 1</div>
<div id="div2">This is div 2</div>
<div id="div3">This is div 3</div>
<div id="div4">This is div 4</div>
</div>
</div>
<div class="nav">
<button type="button" id="add">Add to Deck</button>
</div>
</div>
</body>
</html>
The coverflow function (included as a js file in the head section) is here. When I click the button, I was expecting it to add a DIV to the already present deck. For some reason, it doesn't show the newly added DIV. I tried calling the coverflow() function after I added the new element but that didn't work either. The modified coverflow function is given here:
;(function($){
$.widget("ui.coverflow", {
init: function() {
var self = this;
this.items = $(this.options.items, this.element).bind("click", function() {
self.moveTo(this);
//$("div.slider").slider("moveTo", self.current, null, true);
});
this.itemWidth = this.items.outerWidth(true);
this.current = 0; //Start item
this.refresh(1, 0, this.current);
this.element.css("left",
(-this.current * this.itemWidth/2)
+ (this.element.parent()[0].offsetWidth/2 - this.itemWidth/2) //Center the items container
- (parseInt(this.element.css("paddingLeft")) || 0) //Subtract the padding of the items container
);
},
moveTo: function(item) {
this.previous = this.current;
this.current = !isNaN(parseInt(item)) ? parseInt(item) : this.items.index(item);
if(this.previous == this.current) return false; //Don't animate when clicking on the same item
var self = this, to = Math.abs(self.previous-self.current) <=1 ? self.previous : self.current+(self.previous < self.current ? -1 : 1);
$.fx.step.coverflow = function(fx) {
self.refresh(fx.now, to, self.current);
};
this.element.stop().animate({
coverflow: 1,
left: (
(-this.current * this.itemWidth/2)
+ (this.element.parent()[0].offsetWidth/2 - this.itemWidth/2) //Center the items container
- (parseInt(this.element.css("paddingLeft")) || 0) //Subtract the padding of the items container
)
}, {
duration: 1000,
easing: "easeOutQuint"
});
/*current = this.current;
$("[id^=div]").each(function() {
if(this.id != "div"+current) {
console.info(this.id + " Current: " + current);
$(this).fadeTo( 'slow', 0.1);
}
});*/
},
refresh: function(state,from,to) {
var self = this, offset = null;
this.items.each(function(i) {
var side = (i == to && from-to < 0 ) || i-to > 0 ? "left" : "right";
var mod = i == to ? (1-state) : ( i == from ? state : 1 );
var before = (i > from && i != to);
$(this).css({
webkitTransform: "matrix(1,"+(mod * (side == "right" ? -0.5 : 0.5))+",0,1,0,0) scale("+(1+((1-mod)*0.5))+")",
left: (
(-i * (self.itemWidth/2))
+ (side == "right"? -self.itemWidth/2 : self.itemWidth/2) * mod //For the space in the middle
),
zIndex: self.items.length + (side == "left" ? to-i : i-to)
});
if(!$.browser.msie)
$(this).css("opacity", 1 - Math.abs((side == "left" ? to-i : i-to))/2);
});
}
});
$.extend($.ui.coverflow, {
defaults: {
items: "> *"
}
});
})(jQuery);
One thing I did notice is that after clicking the button for about 5-10 times, the elements show up but not along with the already present divs but rather below them. I am guessing that this has something to do with the CSS of the magnifyme class (2000px), but I am not sure what it is. Is there any way I can make this work?
You need to write an additional function for the coverflow widget:
add: function(el) {
var self = this;
this.element.append(el)
this.options.items = $('> *', this.element);
this.items = $(this.options.items, this.element).bind("click", function() {
self.moveTo(this);
});
this.itemWidth = this.items.outerWidth(true);
this.moveTo(this.items.length-1);
},
and then call it like so:
$("#add").click(function() {
$("div.magnifyme").coverflow('add', "<div></div>");
});
First, you need to add a references to the jQuery UI core, and it also appears that it requires the jQuery slider plugin.
Second, in your click event you're doing a location.reload, which is refreshing the page from the server, resetting any changes you had made to the page. (if you make the DIVs much smaller you can see one flash in before the page is reloaded).
You are getting a js error on the page -- "$.widget is not a function" because you didn't include the jqueryUI library. http://jqueryui.com/
Also if you remove the location.reload line, your code will work, however, I would rewrite that script block like this, so that everything clearly runs when the document is ready:
<script type="text/javascript">
$(document).ready(function() {
$("div.magnifyme").coverflow();
$("#add").click(function() {
$(".magnifyme").append("<div id=\"div5\">hello world</div>");
$("div.magnifyme").coverflow();
});
});
</script>