I'm trying to do a carousal like in this CodePen using React Hooks.
My present result is in this Sandbox: Click..!
The problems I'm facing are:
I don't know how to make that CSS animation effect of the letters coming and forming the text and scattering back as in the CodePen example.
I want to include the description part also which is in the description={data.desc}. Do I have to make the split again or any easy method to split both title and description together. I lag knowledge here.
My code is as below:
import React from "react";
export default function SlideCard(props) {
const { id, idx, title } = props;
function mainText() {
return (
<div style={{ border: "2px solid gold" }}>
<h1>{title}</h1>
</div>
);
}
//console.log(id);
function scatter() {
return (
<div>
{title.split("").map((item, index) => {
const style = {
position: "absolute",
top: Math.floor(Math.random() * 200) + "px",
left: Math.floor(Math.random() * 400) + "px",
zIndex: "initial",
color: "#AAA",
overflow: "hidden",
transition: "left 2s, top 2s, color 2s"
};
return (
<div key={index}>
<div className="scatter" style={style}>
{item}
</div>
</div>
);
})}
</div>
);
}
return (
<div>
<div>{idx === id && mainText()}</div>
{idx !== id && scatter()}
</div>
);
}
He's maintaining two same copies of each page data. One with class .position-data and one with .mutable. .position-data is hidden and only used for getting coordinates to bring back .mutable letters together.
Here is the simplified version of the CodePen example:
$(document).ready(function() {
assemble();
});
function scatter() {
for (var i = 0; i < 3; i++) {
var randLeft = Math.floor(Math.random() * $(window).width());
var randTop = Math.floor(Math.random() * $(window).height());
//randomly position .mutable elements
$(".mutable > span:eq(" + i + ")").animate({
left: randLeft,
top: randTop,
color: "#0005"
}, 2000, "easeInBack");
}
}
function assemble() {
for (var i = 0; i < 3; i++) {
$(".mutable > span:eq(" + i + ")").animate({
//get center position from .position data marked elements
left: $(".position-data > span:eq(" + i + ")").offset().left + "px",
top: $(".position-data > span:eq(" + i + ")").offset().top + "px",
color: "#000"
}, 2000, 'easeOutBounce');
}
}
span {
font-size: 30px;
}
.position-data {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
opacity: 0.4;
color: green;
}
.mutable span {
position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<div class="position-data">
<span>a</span>
<span>b</span>
<span>c</span>
</div>
<div class="mutable shadowed">
<span>a</span>
<span>b</span>
<span>c</span>
</div>
<button onclick="scatter()">Scatter</button>
<button onclick="assemble()">Assemble</button>
I want to position the actively displaying Text container to the centre of the carousal.
The actively displaying text container is marked with .mutable class which has following css:
.mutable {
position: absolute;
overflow: hidden;
display: inline-block;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
So they all have full size of the document body. Using javascript function arrangeCurrentPage() in codepen they are set with coordinates such that they look centered.
I don't know how to make that transition effect of the letters coming and forming the text and scattering back as in the CodePen example.
Refer to above simplified code. Use the buttons to see the effects separately. All letter elements are put in a div with class .mutable. All letters are position: absolute; so they are free to move anywhere. In javascript function scatter() I am simply assigning top and left properties to random coordinates. With animation effect they scatter smoothly. In codepen he is achieving the animation effect using css transition transition: left 2s, top 2s, color 2s;
To bring them back simply us css selector nth-child .position-data > span:eq(n) to get corresponding coordinates of the character. Refer javascript function assemble().
I want to include the description part also which is in the description={data.desc}. Do I have to make the split again or any easy method to split both title and description together. I lag knowledge here.
As title and description will be displayed separately with separate presentation styles. Code will be cleaner if you keep split versions of them separately. You can create utility methods like split(text), scramble(array), arrange(array)and use it for both like cramble(titleArray)and scramble(descArray).
If we use 'position:relative' on letters we don't have to maintain two copies of same data:
<!DOCTYPE html>
<head>
<title>Document</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script>
$(document).ready(function() {
assemble();
});
function randomX() {
return Math.floor(Math.random() * $(window).width() * 0.7) - $(window).width() * 0.25;
}
function randomY() {
return Math.floor(Math.random() * $(window).height() * 0.7) - $(window).height() * 0.25;
}
function scatter() {
for (var i = 0; i < 3; i++) {
$(".mutable > span:eq(" + i + ")").animate({
left: randomX(),
top: randomY(),
color: "#f118"
}, 2000, "easeInBack");
}
}
function assemble() {
for (var i = 0; i < 3; i++) {
$(".mutable > span:eq(" + i + ")").animate({
left: '0px',
top: '0px',
color: "#000"
}, 2000, 'easeOutBounce');
}
}
</script>
<style>
span {
font-size: 30px;
}
.mutable {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.mutable span {
position: relative; /* <--- */
}
</style>
</head>
<body>
<div class="mutable">
<span>a</span>
<span>b</span>
<span>c</span>
</div>
<button onclick="scatter()">Scatter</button>
<button onclick="assemble()">Assemble</button>
</body>
</html>
The sandbox demo you want to emulate is using an animation they call Alphabet Soup. After a quick google search, I found an npm package that can help you implement this in your react component: https://github.com/OrigenStudio/react-alphabet-soup.
Why reinvent the wheel?
Related
I have a HTML and I'm trying to randomize each layer top margin attribute.
function randomize() {
let r;
let list = document.querySelectorAll("span");
for (let i = 0; i < list.length; i++) {
r = Math.floor(Math.random() * 50);
list.forEach((list) => {
style.top = `${r} + px`;
});
}
}
span {
position: absolute;
height: 20px;
width: 20px;
border-radius: 100%;
z-index: -2;
}
<div class="parallax">
<span class="layer" data-speed="-5">10110</span>
<span class="layer" data-speed="-5">0</span>
</div>
What am I getting wrong here? I can't find the proper solution.
A few things:
To use the top CSS property, the element needs to have a position defined. You can set that in the CSS (position: relative) or set it in the JS. (EDIT OP added CSS that they had already which set the position. Leaving this here for people that use top without setting an element's position)
You need to move the randomization into the forEach otherwise it will have the same value for all span elements
You need to attach the style prop to the element you are passing in the forEach, e.g., list.style.styleProp
function randomize() {
let r;
let list = document.querySelectorAll("span");
for (let i = 0; i < list.length; i++) {
list.forEach((list) => {
r = Math.floor(Math.random() * 50);
list.style.top = r + 'px';
});
}
}
randomize();
span {
position: absolute;
height: 20px;
width: 20px;
border-radius: 100%;
z-index: -2;
}
<div class="parallax">
<span class="layer" data-speed="-5">10110</span>
<span class="layer" data-speed="-5">0</span>
</div>
Because <span> is natively an inline element, and margin has no effect.
Change your <span>s to <div>s.
I am trying to make a transition with a div that should grow and overlap a text.
Here are my codes
const box = document.querySelector("#box");
const mybutt = document.querySelector("#mybutt");
mybutt.addEventListener("click", transitionfunction);
function transitionfunction() {
if(box.style.height != "100px"){
box.style.height = "100px";
box.style.transition = "2s";
}
else {
box.style.height = "50px";
box.style.transition = "2s";
}
}
#box {
background: red;
height: 50px;
width: 50px;
}
#para {
postion: fixed;
}
<div id="parentdiv">
<div id="box"></div>
<p id="para">Help</p>
</div>
<button id="mybutt">click</button>
At the moment, on the click of the button, both the button and the paragraph para move down, I want them to be fixed and I want the div, #box to cover the para but its not working. I tried putting it to fixed but doesnt work. And on the click on the button again, it should reveal the text again.
If you use position: fixed;, you should manually set the top property.
To make a div overlay some text, use z-index
const box = document.querySelector("#box");
const mybutt = document.querySelector("#mybutt");
mybutt.addEventListener("click", transitionfunction);
function transitionfunction() {
if (box.style.height != "100px"){
box.style.height = "100px";
box.style.transition = "2s";
} else {
box.style.height = "50px";
box.style.transition = "2s";
}
}
#mybutt {
position: fixed;
top: 120px;
}
#box {
background: red;
position: fixed;
height: 50px;
width: 50px;
z-index: 2;
}
#para {
position: fixed;
z-index: 1;
top: 60px;
}
<div id="parentdiv">
<div id="box"></div>
<p id="para">Help</p>
</div>
<button id="mybutt">click</button>
Firstly, you spelled "position" wrong for #para. Change it to:
#para {
position: absolute;
top: 10%;
}
This will keep the paragraph positioned in one spot; it won't move.
Fixed will work, although you might want to use 'absolute' instead if you want it to anchored to it's parent instead of the window itself.
Also, 'position' is misspelled; not sure if it is in your testing code.
The 'top' property has to be set for the element to know where to anchor itself, the 'position' property is what to anchor to.
HTML
<div id="parentdiv">
<div id="box"></div>
<p id="para">Help</p>
</div>
</div>
<button id="mybutt">click</button>
CSS
<style>
#box {
background: red;
height: 50px;
width: 50px;
}
#para {
position: absolute;
top:70;
}
</style>
*You also might want to move '#para' outside '#parentdiv', but it depends what you'll trying to ultimately do, it does work inside too.
Added:
To include an alert at 75px, you have to use a function that gives you more granular control(as far as I know at least). This is one solution:
<script>
const box = document.querySelector("#box");
const mybutt = document.querySelector("#mybutt");
mybutt.addEventListener("click", transitionfunction);
var intHeight = $("#box").css("height").split("p")[0];
function transitionfunction() {
if(intHeight < 100) {
intHeight++;
$("#box").css("height", intHeight + "px");
if (intHeight===76)
alert("75px!")
requestAnimationFrame(transitionfunction);
}
intHeight = $("#box").css("height").split("p")[0];
mybutt.addEventListener("click", revtransitionfunction);
mybutt.removeEventListener("click", transitionfunction);
}
function revtransitionfunction() {
if(intHeight >= 50) {
intHeight--;
$("#box").css("height", intHeight + "px");
if (intHeight===74)
alert("75px!")
requestAnimationFrame(revtransitionfunction);
}
intHeight = $("#box").css("height").split("p")[0];
mybutt.addEventListener("click", transitionfunction);
mybutt.removeEventListener("click", revtransitionfunction);
}
So I have a set of elements called .project-slide, one after the other. Some of these will have the .colour-change class, IF they do have this class they will change the background colour of the .background element when they come into view. This is what I've got so far: https://codepen.io/neal_fletcher/pen/eGmmvJ
But I'm looking to achieve something like this: http://studio.institute/clients/nike/
Scroll through the page to see the background change. So in my case what I'd want is that when a .colour-change was coming into view it would slowly animate the opacity in of the .background element, then slowly animate the opacity out as I scroll past it (animating on scroll that is).
Any suggestions on how I could achieve that would be greatly appreciated!
HTML:
<div class="project-slide fullscreen">
SLIDE ONE
</div>
<div class="project-slide fullscreen">
SLIDE TWO
</div>
<div class="project-slide fullscreen colour-change" data-bg="#EA8D02">
SLIDE THREE
</div>
<div class="project-slide fullscreen">
SLIDE TWO
</div>
<div class="project-slide fullscreen colour-change" data-bg="#cccccc">
SLIDE THREE
</div>
</div>
jQuery:
$(window).on('scroll', function () {
$('.project-slide').each(function() {
if ($(window).scrollTop() >= $(this).offset().top - ($(window).height() / 2)) {
if($(this).hasClass('colour-change')) {
var bgCol = $(this).attr('data-bg');
$('.background').css('background-color', bgCol);
} else {
}
} else {
}
});
});
Set some data-gb-color with RGB values like 255,0,0…
Calculate the currently tracked element in-viewport-height.
than get the 0..1 value of the inViewport element height and use it as the Alpha channel for the RGB color:
/**
* inViewport jQuery plugin by Roko C.B.
* http://stackoverflow.com/a/26831113/383904
* Returns a callback function with an argument holding
* the current amount of px an element is visible in viewport
* (The min returned value is 0 (element outside of viewport)
*/
;
(function($, win) {
$.fn.inViewport = function(cb) {
return this.each(function(i, el) {
function visPx() {
var elH = $(el).outerHeight(),
H = $(win).height(),
r = el.getBoundingClientRect(),
t = r.top,
b = r.bottom;
return cb.call(el, Math.max(0, t > 0 ? Math.min(elH, H - t) : (b < H ? b : H)), H);
}
visPx();
$(win).on("resize scroll", visPx);
});
};
}(jQuery, window));
// OK. Let's do it
var $wrap = $(".background");
$("[data-bg-color]").inViewport(function(px, winH) {
var opacity = (px - winH) / winH + 1;
if (opacity <= 0) return; // Ignore if value is 0
$wrap.css({background: "rgba(" + this.dataset.bgColor + ", " + opacity + ")"});
});
/*QuickReset*/*{margin:0;box-sizing:border-box;}html,body{height:100%;font:14px/1.4 sans-serif;}
.project-slide {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.project-slide h2 {
font-weight: 100;
font-size: 10vw;
}
<div class="project-slides-wrap background">
<div class="project-slide">
<h2>when in trouble...</h2>
</div>
<div class="project-slide" data-bg-color="0,200,255">
<h2>real trouble...</h2>
</div>
<div class="project-slide">
<h2>ask...</h2>
</div>
<div class="project-slide" data-bg-color="244,128,36">
<h2>stack<b>overflow</b></h2>
</div>
</div>
<script src="//code.jquery.com/jquery-3.1.0.js"></script>
Looks like that effect is using two fixed divs so if you need something simple like that you can do it like this:
But if you need something more complicated use #Roko's answer.
var fixed = $(".fixed");
var fixed2 = $(".fixed2");
$( window ).scroll(function() {
var top = $( window ).scrollTop();
var opacity = (top)/300;
if( opacity > 1 )
opacity = 1;
fixed.css("opacity",opacity);
if( fixed.css('opacity') == 1 ) {
top = 0;
opacity = (top += $( window ).scrollTop()-400)/300;
if( opacity > 1 )
opacity = 1;
fixed2.css("opacity",opacity);
}
});
.fixed{
display: block;
width: 100%;
height: 200px;
background: blue;
position: fixed;
top: 0px;
left: 0px;
color: #FFF;
padding: 0px;
margin: 0px;
opacity: 0;
}
.fixed2{
display: block;
width: 100%;
height: 200px;
background: red;
position: fixed;
top: 0px;
left: 0px;
color: #FFF;
padding: 0px;
margin: 0px;
opacity: 0;
}
.container{
display: inline-block;
width: 100%;
height: 2000px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
Scroll me!!
</div>
<div class="fixed">
</div>
<div class="fixed2">
</div>
I attempted to add a swiping function to my slider to allow users to swipe through the images on their touchable devices. It hasn't turned out the best. When swiping at the images they do not slide over all of the way and then when I get to the end of the gallery (end of fourth image), the slider goes blank (goes white) and then it goes back to normal after a while.
I have added the important code to this question, as well as added a Fiddle to try it out.
The fiddle doesn't replicate the issue, so if you would like to see what this is doing, please go here to see it live. Scroll about halfway down and then you will see the slider.
The example I used had three images instead of four and I am thinking this may be my issue, but when I remove my 4th image (a repeat of the first image for a smoother transition back to the first), the issue is still present. I'm 99% sure the issue resides within the javascript, but I can't locate it.
Does anyone see what I am doing wrong or how to improve this?
Please note. I am putting the full code for this function, but I believe the issue resides within the move or end function here:
move: function(event) {
// Continuously return touch position.
this.touchmovex = event.originalEvent.touches[0].pageX;
// Calculate distance to translate figure.
this.movex = this.index*this.slideWidth + (this.touchstartx - this.touchmovex);
// Defines the speed the images should move at.
var panx = 100-this.movex/6; // was /6
if (this.movex < 600) { // Makes the figure stop moving when there is no more content.
this.el.figure.css('transform','translate3d(-' + this.movex + 'px,0,0)');
}
if (panx < 100) { // Corrects an edge-case problem where the background image moves without the container moving.
this.el.imgSlide.css('transform','translate3d(-' + panx + 'px,0,0)');
}
},
end: function(event) {
// Calculate the distance swiped.
var absMove = Math.abs(this.index*this.slideWidth - this.movex);
// Calculate the index. All other calculations are based on the index.
if (absMove > this.slideWidth/2 || this.longTouch === false) {
if (this.movex > this.index*this.slideWidth && this.index < 2) {
this.index++;
} else if (this.movex < this.index*this.slideWidth && this.index > 0) {
this.index--;
}
}
// Move and animate the elements.
this.el.figure.addClass('animate').css('transform', 'translate3d(-' + this.index*this.slideWidth + 'px,0,0)');
this.el.imgSlide.addClass('animate').css('transform', 'translate3d(-' + 100-this.index*50 + 'px,0,0)');
Full code:
if (navigator.msMaxTouchPoints) {
$('#slider').addClass('ms-touch');
$('#slider').on('scroll', function() {
$('.slide-image').css('transform','translate3d(-' + (100-$(this).scrollLeft()/6) + 'px,0,0)');
});
} else {
var slider = {
el: {
slider: $("#slider"),
figure: $(".figure"),
imgSlide: $(".slide-image")
},
slideWidth: $('#slider').width(),
touchstartx: undefined,
touchmovex: undefined,
movex: undefined,
index: 0,
longTouch: undefined,
init: function() {
this.bindUIEvents();
},
bindUIEvents: function() {
this.el.figure.on("touchstart", function(event) {
slider.start(event);
});
this.el.figure.on("touchmove", function(event) {
slider.move(event);
});
this.el.figure.on("touchend", function(event) {
slider.end(event);
});
},
start: function(event) {
// Test for flick.
this.longTouch = false;
setTimeout(function() {
window.slider.longTouch = true;
}, 250);
// Get the original touch position.
this.touchstartx = event.originalEvent.touches[0].pageX;
// The movement gets all janky if there's a transition on the elements.
$('.animate').removeClass('animate');
},
move: function(event) {
// Continuously return touch position.
this.touchmovex = event.originalEvent.touches[0].pageX;
// Calculate distance to translate figure.
this.movex = this.index*this.slideWidth + (this.touchstartx - this.touchmovex);
// Defines the speed the images should move at.
var panx = 100-this.movex/6; // was /6
if (this.movex < 600) { // Makes the figure stop moving when there is no more content.
this.el.figure.css('transform','translate3d(-' + this.movex + 'px,0,0)');
}
if (panx < 100) { // Corrects an edge-case problem where the background image moves without the container moving.
this.el.imgSlide.css('transform','translate3d(-' + panx + 'px,0,0)');
}
},
end: function(event) {
// Calculate the distance swiped.
var absMove = Math.abs(this.index*this.slideWidth - this.movex);
// Calculate the index. All other calculations are based on the index.
if (absMove > this.slideWidth/2 || this.longTouch === false) {
if (this.movex > this.index*this.slideWidth && this.index < 2) {
this.index++;
} else if (this.movex < this.index*this.slideWidth && this.index > 0) {
this.index--;
}
}
// Move and animate the elements.
this.el.figure.addClass('animate').css('transform', 'translate3d(-' + this.index*this.slideWidth + 'px,0,0)');
this.el.imgSlide.addClass('animate').css('transform', 'translate3d(-' + 100-this.index*50 + 'px,0,0)');
}
};
slider.init();
}
.animate {
transition: transform 0.3s ease-out;
}
#company-slider-section {
width: 100%;
height: auto;
position: relative;
}
div#slider {
width: 100%;
overflow: hidden;
position: relative;
}
div#slider .figure {
position: relative;
width: 400%;
margin: 0;
padding: 0;
font-size: 0;
text-align: left;
}
.ms-touch.slider {
overflow-x: scroll;
overflow-y: hidden;
-ms-overflow-style: none;
/* Hides the scrollbar. */
-ms-scroll-chaining: none;
/* Prevents Metro from swiping to the next tab or app. */
-ms-scroll-snap-type: mandatory;
/* Forces a snap scroll behavior on your images. */
-ms-scroll-snap-points-x: snapInterval(0%, 100%);
/* Defines the y and x intervals to snap to when scrolling. */
}
.figure2 {
animation: 20s company-slider infinite;
margin: 0;
}
#keyframes company-slider {
0% {
left: 0%;
}
30% {
left: 0%;
}
35% {
left: -100%;
}
55% {
left: -100%;
}
60% {
left: -200%;
}
90% {
left: -200%;
}
95% {
left: -300%;
}
100% {
left: -300%;
}
}
.slide-wrapper img {
width: 25%;
min-height: 100%;
float: left;
position: relative;
overflow: hidden;
}
.slide {
height: 100%;
position: relative;
}
.slide:before {
content: "";
position: absolute;
z-index: 1;
bottom: 0;
left: 0;
width: 100%;
height: 40%;
background: linear-gradient(transparent, black);
}
<div id="company-slider-section">
<div class="section-blocks left">
<div id="slider" class="slider">
<figure class="figure figure2">
<div class="slide-wrapper">
<div class="slide"><img src="/images/work/projects/eslich/es-test1.jpg" alt class="slide-image"></div>
</div>
<div class="slide-wrapper">
<div class="slide"><img src="/images/work/projects//desktop-service.jpg" alt class="slide-image"></div>
</div>
<div class="slide-wrapper">
<div class="slide"><img src="/images/work/projects//es-test2.jpg" alt class="slide-image"></div>
</div>
<div class="slide-wrapper">
<div class="slide"><img src="/images/work/projects//es-test1.jpg" alt class="slide-image"></div>
</div>
</figure>
</div>
</div>
</div>
After studying, looking at tutorials, getting some help here, I almost got this script working as intended. However, I'm not at a stand still and my brain hurts trying to figure out the logic.
The problem is the script allows for over scrolling forward. How can I stop that?
jQuery:
var $item = $('.slider'),
start = 0,
view = $('#main-header').width(),
end = $('.slider').width();
$('.next').click(function () {
if (start < view) {
start++;
$item.animate({
'left': '-=100%'
});
}
});
$('.prev').click(function () {
if (start > 0) {
start--;
$item.animate({
'left': '+=100%'
});
}
});
HTML:
<div id="main-header">
<div class="slider">
<div class="item-post" style="background: url(http://4.bp.blogspot.com/-LjJWOy7K-Q0/VOUJbMJr0_I/AAAAAAAAdAg/I2V70xea8YE/s320-c/enviroment-5.jpg) center"></div>
<div class="item-post" style="background: url(http://1.bp.blogspot.com/-l3UnbspFvv0/VOUK8M-34UI/AAAAAAAAdA0/ooGyXrHdNcg/s320-c/enviroment-2.jpg)"></div>
<div class="item-post" style="background: url(http://2.bp.blogspot.com/-cun1kQ42IBs/VOUaSPfnebI/AAAAAAAAdBQ/yTEj9K-BGdk/s320-c/fashion-3.jpg)"></div>
</div>
<div class="prev"></div>
<div class="next"></div>
</div>
CSS:
#main-header {
overflow: hidden;
position: relative;
}
.slider {
width: 100%;
height: 200px;
position: relative;
}
.item-post {
width: 100%;
height: 200px;
background: rgba(0, 0, 0, 0.1);
background-size: cover !important;
background-position: center !important;
position: absolute;
top: 0;
}
.item-post:first-of-type {
left: 0;
}
.item-post:nth-of-type(2) {
left: 100%;
}
.item-post:last-of-type {
left: 200%;
}
.prev, .next {
position: absolute;
top: 0;
bottom: 0;
width: 25px;
background: rgba(0, 0, 0, 0.2);
cursor: pointer;
}
.prev {
left: 0;
}
.next {
right: 0;
}
jsfiddle: http://jsfiddle.net/51maaks8/8/
In order to determine whether there is another slide visible, you could create a function that adds the .offsetLeft value of the parent element to the .offsetLeft value of the last visible slide element and its width. You would then subtract the width of the parent element from the sum of these calculations.
In doing so, you are essentially calculating the position of the last slide element relative to the left positioning of the .item-wrapper parent element.
function moreVisibleSlides() {
var $last = $('#slider > .item-wrapper > .item-post:last:visible'),
positionRelativeToParent = $last.parent()[0].offsetLeft + $last[0].offsetLeft + $last.width() - $item.width();
return positionRelativeToParent > 5;
}
For the click event listener, only slide the element if there are more visible slides, which is determined by the boolean returned by the moreVisibleSlides function. In addition, I also added a check (!$item.is(':animated')) to prevent the next slide from being animated if there is currently an animation in progress. This ensures that you can't click the .next button multiple times during an animation and then over scroll regardless of whether or not there are more visible slides.
Updated Example
$('.next').click(function () {
if (moreVisibleSlides() && !$item.is(':animated')) {
start++;
$item.animate({
'left': '-=100%'
});
}
});