I am trying to create a slot machine using the following jquery plugin: jquery slot machine
I started with the simple Demo und entered my own list. The Problem I am having is that I need more than just that block which shows 1 line of the list. I need to show what is above and beneath the middle line of the lists. So I made the jSlotsWrapper box bigger.
Now I have the problem that when the lists spin, at the end of the list you see empty space. How can I make that the list has no end? So where the last item in the list is, I want to start again with the list.
EDIT
here is my html file
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Datengut Spielautomat</title>
<style type="text/css">
body {
text-align: center;
position: absolute;
height: 600px;
margin: auto;
top: 0; left: 0; bottom: 0; right: 0;
}
ul {
padding: 0;
margin: 0;
list-style: none;
}
li {
height: 62px;
}
.jSlots-wrapper {
overflow: hidden;
text-align: center;
font-family:arial,helvetica,sans-serif;
font-size: 40px;
text-shadow: 2px 2px 2px #888888;
height: 600px;
width: 1242px;
margin: 10px auto;
border: 2px solid;
border-color: #ffa500;
box-shadow: 5px 5px 5px #888888;
box-shadow: inset 0 200px 100px -100px #555555, inset 0 -200px 100px -100px #555555;
}
.jSlots-wrapper::after {
content: "";
background:url("blumen.jpg");
opacity: 0.5;
z-index: -1;
}
.slot {
z-index: -1;
width: 410px;
text-align: center;
margin-left: 5px auto;
margin-right: 5px auto;
float: left;
border-left: 2px solid;
border-right: 2px solid;
border-color: #ffa500;
}
.line {
width: 410px;
height: 2px;
-webkit-transform:
translateY(-20px)
translateX(5px)
}
</style>
</head>
<body>
<ul class="slot">
<li>Bauakte</li>
<li></li>
<li>Bautagebuch</li>
<li></li>
<li>Mängelverwaltung</li>
<li></li>
<li>Störungsverwaltung</li>
<li></li>
<li>Personalakte</li>
<li></li>
<li>Maschinenakte</li>
<li></li>
</ul>
<script src="jquery.1.6.4.min.js" type="text/javascript" charset="utf-8"></script>
<script src="jquery.easing.1.3.js" type="text/javascript" charset="utf-8"></script>
<script src="jquery.jSlots.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
// normal example
$('.slot').jSlots({
number : 3,
spinner : 'body',
spinEvent : 'keypress',
easing: 'easeOutSine',
time : 7000,
loops : 6,
});
</script>
</body>
</html>
and here is my js file:
(function($){
$.jSlots = function(el, options){
var base = this;
base.$el = $(el);
base.el = el;
base.$el.data("jSlots", base);
base.init = function() {
base.options = $.extend({},$.jSlots.defaultOptions, options);
base.setup();
base.bindEvents();
};
// --------------------------------------------------------------------- //
// DEFAULT OPTIONS
// --------------------------------------------------------------------- //
$.jSlots.defaultOptions = {
number : 3, // Number: number of slots
winnerNumber : 1, // Number or Array: list item number(s) upon which to trigger a win, 1-based index, NOT ZERO-BASED
spinner : '', // CSS Selector: element to bind the start event to
spinEvent : 'click', // String: event to start slots on this event
onStart : $.noop, // Function: runs on spin start,
onEnd : $.noop, // Function: run on spin end. It is passed (finalNumbers:Array). finalNumbers gives the index of the li each slot stopped on in order.
onWin : $.noop, // Function: run on winning number. It is passed (winCount:Number, winners:Array)
easing : 'swing', // String: easing type for final spin
time : 7000, // Number: total time of spin animation
loops : 6 // Number: times it will spin during the animation
};
// --------------------------------------------------------------------- //
// HELPERS
// --------------------------------------------------------------------- //
base.randomRange = function(low, high) {
return Math.floor( Math.random() * (1 + high - low) ) + low;
};
// --------------------------------------------------------------------- //
// VARS
// --------------------------------------------------------------------- //
base.isSpinning = false;
base.spinSpeed = 0;
base.winCount = 0;
base.doneCount = 0;
base.$liHeight = 0;
base.$liWidth = 0;
base.winners = [];
base.allSlots = [];
// --------------------------------------------------------------------- //
// FUNCTIONS
// --------------------------------------------------------------------- //
base.setup = function() {
// set sizes
var $list = base.$el;
var $li = $list.find('li').first();
base.$liHeight = $li.outerHeight();
base.$liWidth = $li.outerWidth();
base.liCount = base.$el.children().length;
base.listHeight = base.$liHeight * base.liCount;
base.increment = (base.options.time / base.options.loops) / base.options.loops;
$list.css('position', 'relative');
$li.clone().appendTo($list);
base.$wrapper = $list.wrap('<div class="jSlots-wrapper"></div>').parent();
// remove original, so it can be recreated as a Slot
base.$el.remove();
// clone lists
for (var i = base.options.number - 1; i >= 0; i--){
base.allSlots.push( new base.Slot() );
}
};
base.bindEvents = function() {
$(base.options.spinner).bind(base.options.spinEvent, function(event) {
if (event.which == 32) {
if (!base.isSpinning) {
base.playSlots();
}
}
});
};
// Slot constructor
base.Slot = function() {
this.spinSpeed = 0;
this.el = base.$el.clone().appendTo(base.$wrapper)[0];
this.$el = $(this.el);
this.loopCount = 0;
this.number = 0;
};
base.Slot.prototype = {
// do one rotation
spinEm : function() {
var that = this;
that.$el
.css( 'top', -base.listHeight )
.animate( { 'top' : '0px' }, that.spinSpeed, 'linear', function() {
that.lowerSpeed();
});
},
lowerSpeed : function() {
this.spinSpeed += base.increment;
this.loopCount++;
if ( this.loopCount < base.options.loops ) {
this.spinEm();
} else {
this.finish();
}
},
// final rotation
finish : function() {
var that = this;
var endNum = base.randomRange( 1, base.liCount );
while (endNum % 2 == 0) {
endNum = base.randomRange( 1, base.liCount );
}
var finalPos = - ( (base.$liHeight * endNum) - base.$liHeight );
var finalSpeed = ( (this.spinSpeed * 0.5) * (base.liCount) ) / endNum;
that.$el
.css( 'top', -base.listHeight )
.animate( {'top': finalPos}, finalSpeed, base.options.easing, function() {
base.checkWinner(endNum, that);
});
}
};
base.checkWinner = function(endNum, slot) {
base.doneCount++;
// set the slot number to whatever it ended on
slot.number = endNum;
// if its in the winners array
if (
( $.isArray( base.options.winnerNumber ) && base.options.winnerNumber.indexOf(endNum) > -1 ) ||
endNum === base.options.winnerNumber
) {
// its a winner!
base.winCount++;
base.winners.push(slot.$el);
}
if (base.doneCount === base.options.number) {
var finalNumbers = [];
$.each(base.allSlots, function(index, val) {
finalNumbers[index] = val.number;
});
if ( $.isFunction( base.options.onEnd ) ) {
base.options.onEnd(finalNumbers);
}
if ( base.winCount && $.isFunction(base.options.onWin) ) {
base.options.onWin(base.winCount, base.winners, finalNumbers);
}
base.isSpinning = false;
}
};
base.playSlots = function() {
base.isSpinning = true;
base.winCount = 0;
base.doneCount = 0;
base.winners = [];
if ( $.isFunction(base.options.onStart) ) {
base.options.onStart();
}
$.each(base.allSlots, function(index, val) {
this.spinSpeed = 250*index;
this.loopCount = 0;
this.spinEm();
});
};
base.onWin = function() {
if ( $.isFunction(base.options.onWin) ) {
base.options.onWin();
}
};
// Run initializer
base.init();
};
// --------------------------------------------------------------------- //
// JQUERY FN
// --------------------------------------------------------------------- //
$.fn.jSlots = function(options){
if (this.length) {
return this.each(function(){
(new $.jSlots(this, options));
});
}
};
})(jQuery);
The core functionality is the same as in the github repository.
The important part, I think, is the function spinEm:
spinEm : function() {
var that = this;
that.$el
.css( 'top', -base.listHeight )
.animate( { 'top' : '0px' }, that.spinSpeed, 'linear', function() {
that.lowerSpeed();
});
}
here the list is placed above the jSlotsWrapper and with the animate function it moves down. Now what I need is for the animation to continue, and not to place the list at the top again. How can I achieve that.
EDIT
Ok, i tried the following to avoid the empty space, everytime the animation has finished:
spinEm : function() {
var that = this;
that.$el
.css( 'bottom', $("body").height() )
.animate( { 'top' : '0px' }, that.spinSpeed, 'linear', function() {
that.lowerSpeed();
});
}
I try to place the list at the bottom of the box and move it down until the top appears. But somehow the list doesn't really move. It just moves for 1 word and then stops comletely. What is wrong in the animation code?
EDIT
Ok I found the solution to my problem. Apparently, I can't use bottom in the css function. Instead, I used top and calculated the position of the top border of the list. That way I have an animation without all the empty space at the beginning. To avoid the jumping from the bottom to the top of the list I modified the height of the jSlots-Wrapper and the order of the list items, so that the items that are displayed before and after the jump are the same. That way, the user doesn't see the list jumping.
here is my new animate function.
spinEm : function() {
var that = this;
that.$el
.css( 'top', -(base.listHeight - $("body").height()) )
.animate( { 'top' : '0px'}, that.spinSpeed, 'linear', function() {
that.lowerSpeed();
});
}
I found a way to make the animation so that the user doesn't see the jumping. What I did, is, I configured the list in a way so that the beginning and the end are the same. So that when the end of the list is reached and it jumps to the beginning again, there is no difference. The jump is still there, but not visible for the user.
Related
I'm having some issues implementing this template into my MVC application.
https://bootsnipp.com/snippets/featured/pinterest-like-responsive-grid
My CSS and code works fine, but the Javascript doesn't work.
I'm using a partial view to contain the code which looks like this:
#model List<Assignment_3.Models.Word>
<script type="text/javascript" src='#Url.Content("~/Scripts/ResponsiveGrid.js")'></script>
<div class="container">
<div class="row">
<div>
<section id="pinBoot">
#foreach (var word in Model)
{
<ItemTemplate>
<article class="white-panel">
<a href="#Url.Action("Detail", new { id = Word.WordId })">
<img src="#Url.Content(Idiom.Imagepath)" />
</a>
<h4 class="textwrapper">Test</h4>
<p>Language</p>
</article>
</ItemTemplate>
}
</section>
</div>
</div>
</div>
<style>
body {
background-color: #eee;
}
.textwrapper {
word-break: break-all;
}
#pinBoot {
position: relative;
max-width: 100%;
width: 100%;
}
img {
max-width: 100%;
height: auto;
}
.white-panel {
position: absolute;
background: white;
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3);
padding: 10px;
}
.white-panel h1 {
font-size: 1em;
}
.white-panel h1 a {
color: #A92733;
}
.white-panel:hover {
box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.5);
margin-top: -5px;
-webkit-transition: all 0.3s ease-in-out;
-moz-transition: all 0.3s ease-in-out;
-o-transition: all 0.3s ease-in-out;
transition: all 0.3s ease-in-out;
}
</style>
Here is the Javascript file:
$(document).ready(function () {
$('#pinBoot').pinterest_grid({
no_columns: 4,
padding_x: 10,
padding_y: 10,
margin_bottom: 50,
single_column_breakpoint: 700
});
});
usage:
$(document).ready(function () {
$('#blog-landing').pinterest_grid({
no_columns: 4
});
});
; (function ($, window, document, undefined) {
var pluginName = 'pinterest_grid',
defaults = {
padding_x: 10,
padding_y: 10,
no_columns: 3,
margin_bottom: 50,
single_column_breakpoint: 700
},
columns,
$article,
article_width;
function Plugin(element, options) {
this.element = element;
this.options = $.extend({}, defaults, options);
this._defaults = defaults;
this._name = pluginName;
this.init();
}
Plugin.prototype.init = function () {
var self = this,
resize_finish;
$(window).resize(function () {
clearTimeout(resize_finish);
resize_finish = setTimeout(function () {
self.make_layout_change(self);
}, 11);
});
self.make_layout_change(self);
setTimeout(function () {
$(window).resize();
}, 500);
};
Plugin.prototype.calculate = function (single_column_mode) {
var self = this,
tallest = 0,
row = 0,
$container = $(this.element),
container_width = $container.width();
$article = $(this.element).children();
if (single_column_mode === true) {
article_width = $container.width() - self.options.padding_x;
} else {
article_width = ($container.width() - self.options.padding_x *
self.options.no_columns) / self.options.no_columns;
}
$article.each(function () {
$(this).css('width', article_width);
});
columns = self.options.no_columns;
$article.each(function (index) {
var current_column,
left_out = 0,
top = 0,
$this = $(this),
prevAll = $this.prevAll(),
tallest = 0;
if (single_column_mode === false) {
current_column = (index % columns);
} else {
current_column = 0;
}
for (var t = 0; t < columns; t++) {
$this.removeClass('c' + t);
}
if (index % columns === 0) {
row++;
}
$this.addClass('c' + current_column);
$this.addClass('r' + row);
prevAll.each(function (index) {
if ($(this).hasClass('c' + current_column)) {
top += $(this).outerHeight() + self.options.padding_y;
}
});
if (single_column_mode === true) {
left_out = 0;
} else {
left_out = (index % columns) * (article_width +
self.options.padding_x);
}
$this.css({
'left': left_out,
'top': top
});
});
this.tallest($container);
$(window).resize();
};
Plugin.prototype.tallest = function (_container) {
var column_heights = [],
largest = 0;
for (var z = 0; z < columns; z++) {
var temp_height = 0;
_container.find('.c' + z).each(function () {
temp_height += $(this).outerHeight();
});
column_heights[z] = temp_height;
}
largest = Math.max.apply(Math, column_heights);
_container.css('height', largest + (this.options.padding_y +
this.options.margin_bottom));
};
Plugin.prototype.make_layout_change = function (_self) {
if ($(window).width() < _self.options.single_column_breakpoint) {
_self.calculate(true);
} else {
_self.calculate(false);
}
};
$.fn[pluginName] = function (options) {
return this.each(function () {
if (!$.data(this, 'plugin_' + pluginName)) {
$.data(this, 'plugin_' + pluginName,
new Plugin(this, options));
}
});
}
})(jQuery, window, document);
Any tips in getting the Javascript to work would be hugely appreciated!
It is a good practice to have your javascript files right before the closing body tag even though you are using jQuery and other open source libraries. Have you inspected the browser(F12 on windows) to see if the URL that you are pointing to is loading the file on the network? In MVC, you might want to put the JS file inside of bundle.config and referencing them using Bundling and Minification like the following
In Bundle.config
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/bundles/scripts").Include(
"~/Scripts/script.js");
In Application_Start Event
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
and
On the UI
#Scripts.Render("~/bundles/scripts")
This way , your JS files are minified and changes are always reflected onto the UI(Solves caching issues)
If you inspect the output html in your browser, you'll see that the url in your script tag probably doesn't resolve correctly:
<script type="text/javascript" src='#Url.Content("~/Scripts/ResponsiveGrid.js")'>
</script>
You can fix this by using a url relative to the root of the domain.
src="/Scripts/ResponsiveGrid.js"
I have this jquery functions. I want to make it just one function so I can get thesame results by just calling a function and passing some arguements.
As you can see, the function does basically the same thing counting numbers. I would love to just have one function , then parse out arguments to get the same results. something like startcount(arg1, arg2);
var one_countsArray = [2,4,6,7,4252];
var two_countsArray = [3,3,4,7,1229];
var sumemp = one_countsArray.reduce(add, 0);
var sumallis = two_countsArray.reduce(add, 0);
function add(a, b) {
return a + b;
}
var count = 0;
var inTv = setInterval(function(){startCount()},100);
var inTv2 = setInterval(function(){startCount2()},100);
function startCount()
{
if(count == sumemp) {
clearInterval(inTv);
} else {
count++;
}
$('.stats_em').text(count);
}
var count2 = 10;
function startCount2()
{
if(count2 == sumallis) {
clearInterval(inTv2);
} else {
count2++;
}
$('.stats_iss').text(count2);
}
div {
padding:50px 0;
background: #000000;
color: #ffffff;
width: 100px;
height:100px;
border-radius:50%;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<div class="stats_em"></div>
<div class="stats_iss"></div>
How about a very simple jquery plugin
$.fn.countTo = function(arrNums){
var self = this;
function add(a,b){
return a+b;
}
var current = 0;
var max = arrNums.reduce(add,0);
var int = setInterval(function(){
if(current == max)
clearInterval(int);
else
current++;
self.text(current);
},100);
return this;
}
$('.stats_em').countTo([2,4,6,7,4252]);
$('.stats_iss').countTo([3,3,4,7,1229]);
div {
padding:50px 0;
background: #000000;
color: #ffffff;
width: 100px;
height:100px;
border-radius:50%;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<div class="stats_em"></div>
<div class="stats_iss"></div>
When you notice you're rewriting chunks of similar code, moving to one generic function is the right approach! The best way to start is by trying to determine what you're parameters would be:
count and count2 show that you need a start count for your timer to start at
sumemp and sumpallis show that you need to be able to specify a maximum count
inTv and inTv show that you need to be able to set the interval
$('.stats_iss') and $('.stats_em') show that you need to be able to determine the output element
This means your final class, function or jquery extension will at least have a signature that resembles this:
function(startCount, maximumCount, interval, outputElement) { }
Once you've written this, you can paste in the code you already have. (I've replaced your setInterval with a setTimeout, other than that, not much changed)
var createCounter = function(start, max, interval, outputElement) {
var count = start;
var timeout;
var start = function() {
count += 1;
outputElement.text(count);
if (count < max) {
timeout = setTimeout(start, interval);
}
}
var stop = clearTimeout(timeout);
return {
start: start,
stop: stop
}
}
var one_countsArray = [2, 4, 6, 7, 300];
var two_countsArray = [3, 3, 4, 7, 100];
var sumemp = one_countsArray.reduce(add, 0);
var sumallis = two_countsArray.reduce(add, 0);
function add(a, b) {
return a + b;
}
var counters = [
createCounter(0, sumemp, 100, $('.stats_em')),
createCounter(10, sumallis, 100, $('.stats_iss'))
];
counters.forEach(function(counter) {
counter.start();
});
div {
padding: 50px 0;
background: #000000;
color: #ffffff;
width: 100px;
height: 100px;
border-radius: 50%;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<div class="stats_em"></div>
<div class="stats_iss"></div>
I have searched on this site but did not get what I need.
My issue is that I have created a jquery plugin for carousels, its working fine on 1 instance, but if I created multiple instance its only working on last.
ex:
$('#one').smartCarousel(); // its not working
$('#two').smartCarousel(); // its working
Here is the plugin code:
;(function($){
// default options
var defaults = {
slide : 1,
autoPlay : false,
autoPlayTime : 3000,
speed : 400,
next : false,
prev : false,
reverse : false,
show : 4
}
// function
function sc(el, o){
this.config = $.extend({}, defaults, o);
this.el = el;
this.init();
return this;
}
// set init configurations
sc.prototype.init = function(){
$this = this;
// get children
$this.children = $this.el.children();
// wrape element, add basic css properties
$this.el.wrap('<div class="smartCarouselWrapper clearfix"></div>')
.css({
position: 'absolute',
}).parent().css({
height: $this.el.outerHeight(true), // Height is setting on line 57
width: '100%',
overflow: 'hidden',
position: 'relative'
});
// Show element by config
// Calculate width by deviding wraper width
// Set width of items
$elw = $this.el.parent().width()/$this.config.show;
$this.children.each(function(index, el) {
$(this).width($elw);
});
w = $elw*$this.config.slide; // init width
// get width, hadle diffrent width
$this.children.each(function(index, el) {
w += $(this).outerWidth(true);
});
// set lement width
$this.el.width(w);
// Set height for wrapper
$this.el.parent().height($this.el.outerHeight(true));
// check if next handle assigned
if ($this.config.next != false ) {
$(this.config.next).click(function(e) {
e.preventDefault()
$this.next();
});
};
// check if prev handle assigned
if ($this.config.prev != false ) {
$(this.config.prev).click(function(e) {
e.preventDefault()
$this.prev();
});
};
$this.ready();
} // end of inti
sc.prototype.autoPlay = function(){
// if reverse enabled
if (this.config.reverse != false) { this.prev(); } else { this.next(); };
}
// do stuffs when ready
sc.prototype.ready = function(){
if(this.config.autoPlay != false){
this.timeOut = setTimeout('$this.autoPlay()', this.config.autoPlayTime);
}
}
sc.prototype.next = function(){
$this = this;
clearTimeout($this.timeOut);
l = 0; // left
i = 0; // index
// Add width to l from each element, limiting through slide
$this.children.each(function(index, el) {
if (i < $this.config.slide) {
l -= $(this).outerWidth(true);
//Clone first item after last for smooth animation
$this.el.append($this.children.eq(i).clone());
$this.children = $this.el.children();
};
i++;
});
// animat to show next items and appent prev items to end
$this.el.stop().animate({
left: l},
$this.config.speed, function() {
i = 0; // index
$this.children.each(function(index, el) {
if (i < $this.config.slide) {
$this.children.last().remove();
$this.children = $this.el.children();
};
i++;
});
i = 0;
$this.children.each(function(index, el) {
if (i < $this.config.slide) {
$(this).appendTo($this.el);
$this.el.css('left', parseInt($this.el.css('left'))+$(this).outerWidth(true));
};
i++;
});
$this.children = $this.el.children();
$this.ready();
});
} // end of next
sc.prototype.prev = function(){
$this = this;
clearTimeout($this.timeOut);
l = 0; // left
i = 0; // index
//move last item to first through slide
$this.children.each(function(index, el) {
if (i < $this.config.slide) {
//Clone first item after last for smooth animation
$this.el.prepend($this.children.eq(($this.children.length-1)-i).clone());
l -= $this.children.eq(($this.children.length-1)-i).outerWidth(true);
$this.el.css('left', l);
console.log(1);
};
i++;
});
console.log(l);
$this.children = $this.el.children();
// animate back to 0
$this.el.stop().animate({left: 0}, $this.config.speed, function(){
i = 0;
$this.children.each(function(index, el) {
if (i <= $this.config.slide) {
$this.children.eq($this.children.length-i).remove();
};
i++;
});
$this.children = $this.el.children();
$this.ready();
});
} // end of prev
// plugin
if (typeof $.smartCarousel != 'function') {
$.fn.smartCarousel = function(o){
if (this.length > 0) {
new sc(this.first(), o);
};
return this;
}
}else{
console.log('Function already declared.');
return this;
}
}(jQuery))
Here the html:
<ul class="smart-carousel-list clearfix" id="one">
<li><!-- Image here -->
<h3>Premium Quality DATES</h3>
</li>
<li><!-- Image here -->
<h3>Variety of Export Quality RICE</h3>
</li>
<li><!-- Image here -->
<h3>Sports Goods</h3>
</li>
<li><!-- Image here -->
<h3>Surgical Items</h3>
</li>
<li><!-- Image here -->
<h3>Bad Sheets</h3>
</li>
<li><!-- Image here -->
<h3>Towals</h3>
</li>
<li><!-- Image here -->
<h3>Fruits & Vegetable</h3>
</li>
</ul>
HERE IS THE CSS:
`
.smart-carousel{
width: 100%;
position: relative;
}
.smart-carousel-list{
list-style: none;
margin: 0;
padding: 0;
}
.smart-carousel-list li {
float: left;
-webkit-box-sizing: border-box !important; /* Safari/Chrome, other WebKit */
-moz-box-sizing: border-box !important; /* Firefox, other Gecko */
box-sizing: border-box !important; /* Opera/IE 8+ */
}
.smart-carousel-nav{
position: absolute;
top: 0;
z-index: 1000;
opacity: 0;
transition: opacity 0.4s;
width: 100%;
}
.smart-carousel:hover .smart-carousel-nav{
opacity: 1;
}
.smart-carousel-nav a{
display: block;
width: 29px;
height: 28px;
text-indent: -999999px;
outline: none;
}
.smart-carousel-nav a.sc_next{
background-image: url('next.png');
margin-right: 10px;
float: right;
}
.smart-carousel-nav a.sc_prev{
background-image: url('prev.png');
margin-left: 10px;
float: left;
}
/**
* STYLE FOR TYPE : Images;
*/
.smart-carousel.type-images .smart-carousel-list li img{
max-width: 100%;
display: block;
margin: 0 auto;
}
/**
* STYLE FOR TYPE : Products;
*/
.smart-carousel.type-products .smart-carousel-list li{
border: solid 1px #efefef;
}
.smart-carousel.type-products .smart-carousel-list li img{
max-width: 100%;
display: block;
margin: 0 auto;
}
.smart-carousel.type-products .smart-carousel-list li h3{
width: 100%;
font-size: 18px;
margin: 0;
padding: 0;
}
.smart-carousel.type-products .smart-carousel-list li h3 a{
display: block;
padding: 10px;
font-weight: bold;
}
.smart-carousel.type-products .smart-carousel-list li h3 a span{
float: right;
font-weight: normal;
}
/**
* STYLE FOR TYPE : Posts;
*/
.smart-carousel.type-posts .smart-carousel-list li{
/*border: solid 1px #efefef;*/
}
.smart-carousel.type-posts .smart-carousel-list li img{
max-width: 100%;
display: block;
margin: 0 auto;
}
.smart-carousel.type-posts .smart-carousel-list li h3{
width: 100%;
font-size: 18px;
margin: 0;
padding: 0;
}
.smart-carousel.type-posts .smart-carousel-list li h3 a{
display: block;
padding: 10px;
font-weight: bold;
text-align: center;
}
.smart-carousel.type-posts .smart-carousel-list li h3 a span{
float: right;
font-weight: normal;
}
`
Your plugin is written to only connect to a single jQuery element at a time. You can improve that like this:
// plugin
if (typeof $.smartCarousel != 'function') {
$.fn.smartCarousel = function (o) {
this.each(function(){
// Connect to each jQuery element
new sc($(this), o);
});
return this;
}
} else {
console.log('Function already declared.');
return this;
}
As for the other problems, you have a single global $this shared all over the place. I added all the missing var $this where required for you and correctly reference it in the timer (via an anonymous function wrapper, so that I can reference the local $this):
JSFiddle: http://jsfiddle.net/TrueBlueAussie/b7u4635x/4/
;
(function ($) {
// default options
var defaults = {
slide: 1,
autoPlay: true,
autoPlayTime: 1000,
speed: 400,
next: false,
prev: false,
reverse: false,
show: 4
}
// function
function sc(el, o) {
this.config = $.extend({}, defaults, o);
this.el = el;
this.init();
return this;
}
// set init configurations
sc.prototype.init = function () {
var $this = this;
// get children
$this.children = $this.el.children();
// wrape element, add basic css properties
$this.el.wrap('<div class="smartCarouselWrapper clearfix"></div>')
.css({
position: 'absolute',
}).parent().css({
height: $this.el.outerHeight(true), // Height is setting on line 57
width: '100%',
overflow: 'hidden',
position: 'relative'
});
// Show element by config
// Calculate width by deviding wraper width
// Set width of items
var $elw = $this.el.parent().width() / $this.config.show;
$this.children.each(function (index, el) {
$(this).width($elw);
});
var w = $elw * $this.config.slide; // init width
// get width, hadle diffrent width
$this.children.each(function (index, el) {
w += $(this).outerWidth(true);
});
// set lement width
$this.el.width(w);
// Set height for wrapper
$this.el.parent().height($this.el.outerHeight(true));
// check if next handle assigned
if ($this.config.next != false) {
$(this.config.next).click(function (e) {
e.preventDefault()
$this.next();
});
};
// check if prev handle assigned
if ($this.config.prev != false) {
$(this.config.prev).click(function (e) {
e.preventDefault()
$this.prev();
});
};
$this.ready();
} // end of inti
sc.prototype.autoPlay = function () {
var $this = this;
// if reverse enabled
if ($this.config.reverse != false) {
$this.prev();
} else {
$this.next();
};
}
// do stuffs when ready
sc.prototype.ready = function () {
var $this = this;
if ($this.config.autoPlay != false) {
$this.timeOut = setTimeout(function(){$this.autoPlay();}, $this.config.autoPlayTime);
}
}
sc.prototype.next = function () {
var $this = this;
clearTimeout($this.timeOut);
var l = 0; // left
var i = 0; // index
// Add width to l from each element, limiting through slide
$this.children.each(function (index, el) {
if (i < $this.config.slide) {
l -= $(this).outerWidth(true);
//Clone first item after last for smooth animation
$this.el.append($this.children.eq(i).clone());
$this.children = $this.el.children();
};
i++;
});
// animat to show next items and appent prev items to end
$this.el.stop().animate({
left: l
},
$this.config.speed, function () {
i = 0; // index
$this.children.each(function (index, el) {
if (i < $this.config.slide) {
$this.children.last().remove();
$this.children = $this.el.children();
};
i++;
});
i = 0;
$this.children.each(function (index, el) {
if (i < $this.config.slide) {
$(this).appendTo($this.el);
$this.el.css('left', parseInt($this.el.css('left')) + $(this).outerWidth(true));
};
i++;
});
$this.children = $this.el.children();
$this.ready();
});
} // end of next
sc.prototype.prev = function () {
var $this = this;
clearTimeout($this.timeOut);
var l = 0; // left
var i = 0; // index
//move last item to first through slide
$this.children.each(function (index, el) {
if (i < $this.config.slide) {
//Clone first item after last for smooth animation
$this.el.prepend($this.children.eq(($this.children.length - 1) - i).clone());
l -= $this.children.eq(($this.children.length - 1) - i).outerWidth(true);
$this.el.css('left', l);
console.log(1);
};
i++;
});
console.log(l);
$this.children = $this.el.children();
// animate back to 0
$this.el.stop().animate({
left: 0
}, $this.config.speed, function () {
i = 0;
$this.children.each(function (index, el) {
if (i <= $this.config.slide) {
$this.children.eq($this.children.length - i).remove();
};
i++;
});
$this.children = $this.el.children();
$this.ready();
});
} // end of prev
// plugin
if (typeof $.smartCarousel != 'function') {
$.fn.smartCarousel = function (o) {
this.each(function () {
new sc($(this), o);
});
return this;
}
} else {
console.log('Function already declared.');
return this;
}
}(jQuery));
//$('.smart-carousel-list').smartCarousel();
$('#one').smartCarousel();
$('#two').smartCarousel();
You have a global variable in your plugin, thus making it impossible for the plugin to work with more than one element because each call to the plugin will overwrite the $this for the previous instance to target the new element.
you simply need to add var in each location where it is missing.
var $this = this;
This will of course break any other place where you attempted to use a global $this (such as the setTimeout('$this.autoplay()',200), so you will need to re-write that portion of the code to not execute autoplay() in that way.
I like to display some numbers as pictures. All numbers are included in one picture.
I started with creating a span for each number and each span get a different class so that I can change the picture for the correct number with the style attribute "background-position".
This is working for me. But now I like to add a little animation to this numbers like count up to the correct value. I can do this for one span (number) but how can I do this for all numbers?
HTML:
<style>
.digit0 { background-position: 0 0; }
.digit1 { background-position: 0 -120px; }
.digit2 { background-position: 0 -240px; }
.digit3 { background-position: 0 -360px; }
.digit4 { background-position: 0 -480px; }
.digit5 { background-position: 0 -600px; }
.digit6 { background-position: 0 -720px; }
.digit7 { background-position: 0 -840px; }
.digit8 { background-position: 0 -960px; }
.digit9 { background-position: 0 -1080px; }
</style>
</head>
<body>
<h1>Examples</h1>
<p>
<div id="number">here</div>
</p>
</body>
Javascript:
<script type="text/javascript">
$(document).ready(function(){
// Your code here
var dd = "5487";
dd = dd.replace(/(\d)/g, '<span class="digit0" id="count$1" style="display: inline-block; height: 20px; line-height: 40px; width: 14px; vertical-align: middle; text-align: center; font: 0/0 a; text-shadow: none; background-image: url(../src/jquery.counter-analog.png); color: transparent; margin: 0;"></span>');
$("#number").html(dd);
count = $("#count4").attr("id").replace("count", "").toString();
var i = 0;
setInterval(function() {
counter();
}, 100);
function counter() {
if(i < count) {
i++;
$("#count4").attr("class", "digit" + i + "");
}
}
});
</script>
This is not possible using pure Javascript.
What you're asking for will have to be performed server-side using something like PHP's GD.
Here's one way to do it. It certainly still has room for efficiency and legibility improvement, here and there (see edit history of this answer for one such improvement :) ). But it's a decent start imho:
// goal digits
var dd = '5487';
// separate digits
var digits = dd.split( '' );
// set some animation interval
var interval = 100;
// create spans for each digit,
// append to div#number and initialize animation
digits.forEach( function( value, index ) {
// create a span with initial conditions
var span = $( '<span>', {
'class': 'digit0',
'data': {
'current': 0,
'goal' : value
}
} );
// append span to the div#number
span.appendTo( $( 'div#number' ) );
// call countUp after interval multiplied by the index of this span
setTimeout( function() { countUp.call( span ); }, index * interval );
} );
// count animation function
function countUp()
{
// the current span we're dealing with
var span = this;
// the current value of the span
var current = span.data( 'current' );
// the end goal digit of this span
var goal = span.data( 'goal' );
// increment the digit, if we've not reached the goal yet
if( current < goal )
{
++current;
span.attr( 'class', 'digit' + current );
span.data( 'current', current );
// call countUp again after interval
setTimeout( function() { countUp.call( span ); }, interval );
}
}
See it in action on jsfiddle
To change the speed of the animation, alter the value of interval.
I've answered another similar question some days ago:
$.fn.increment = function (from, to, duration, easing, complete) {
var params = $.speed(duration, easing, complete);
return this.each(function(){
var self = this;
params.step = function(now) {
self.innerText = now << 0;
};
$({number: from}).animate({number: to}, params);
});
};
$('#count').increment(0, 1337);
Update
If you really want to use images, take this:
$.fn.increment = function (x, y, from, to, duration, easing, complete) {
var params = $.speed(duration, easing, complete);
return this.each(function(){
var self = this;
params.step = function(now) {
self.style.backgroundPosition = x * Math.round(now) + 'px ' + y * Math.round(now) + 'px';
};
$({number: from}).animate({number: to}, params);
});
};
$('#count').increment(0, 120, 9);
I found a jQuery slider plugin that does almost what I need. I need to change the tabs so it is on the right side (by adding an option). Also, I would like to add scrolling to the tabs in case there is more than 3 tabs (also by an option). I am trying to make it look like this which is an artist mock up:
http://i.stack.imgur.com/nR8RY.png
This is the script I am trying to modify with the code below it:
http://jqueryglobe.com/labs/feature_list/
/*
* FeatureList - simple and easy creation of an interactive "Featured Items" widget
* Examples and documentation at: http://jqueryglobe.com/article/feature_list/
* Version: 1.0.0 (01/09/2009)
* Copyright (c) 2009 jQueryGlobe
* Licensed under the MIT License: http://en.wikipedia.org/wiki/MIT_License
* Requires: jQuery v1.3+
*/
;(function($) {
$.fn.featureList = function(options) {
var tabs = $(this);
var output = $(options.output);
new jQuery.featureList(tabs, output, options);
return this;
};
$.featureList = function(tabs, output, options) {
function slide(nr) {
if (typeof nr == "undefined") {
nr = visible_item + 1;
nr = nr >= total_items ? 0 : nr;
}
tabs.removeClass('current').filter(":eq(" + nr + ")").addClass('current');
output.stop(true, true).filter(":visible").fadeOut();
output.filter(":eq(" + nr + ")").fadeIn(function() {
visible_item = nr;
});
}
var options = options || {};
var total_items = tabs.length;
var visible_item = options.start_item || 0;
options.pause_on_hover = options.pause_on_hover || true;
options.transition_interval = options.transition_interval || 5000;
output.hide().eq( visible_item ).show();
tabs.eq( visible_item ).addClass('current');
tabs.click(function() {
if ($(this).hasClass('current')) {
return false;
}
slide( tabs.index( this) );
});
if (options.transition_interval > 0) {
var timer = setInterval(function () {
slide();
}, options.transition_interval);
if (options.pause_on_hover) {
tabs.mouseenter(function() {
clearInterval( timer );
}).mouseleave(function() {
clearInterval( timer );
timer = setInterval(function () {
slide();
}, options.transition_interval);
});
}
}
};
})(jQuery);
This is the CSS:
body {
background: #EEE;
font-family: "Trebuchet MS",Verdana,Arial,sans-serif;
font-size: 14px;
line-height: 1.6;
}
#content {
width: 750px;
margin: 50px auto;
padding: 20px;
background: #FFF;
border: 1px solid #CCC;
}
h1 {
margin: 0;
}
hr {
border: none;
height: 1px; line-height: 1px;
background: #CCC;
margin-bottom: 20px;
padding: 0;
}
p {
margin: 0;
padding: 7px 0;
}
.clear {
clear: both;
line-height: 1px;
font-size: 1px;
}
a {
outline-color: #888;
}
Can anyone help with this?
Answer: jsFiddle: features box that slides and scrolls
Features:
Slides over time
Click next and previous
Support for lots of slides
Smooth scrolling
Move to item on click
Stop movement on hover
Easily extended because it uses the cycle plug-in.
Time spent on project: 4hrs
Ok, no fancy scrollbars or anything, but it will iterate through each one bringing it to the top index. I spent ages getting this working properly.
You can test it by adding additional items to the Lists.
/*
* FeatureList - simple and easy creation of an interactive "Featured Items" widget
* Examples and documentation at: http://jqueryglobe.com/article/feature_list/
* Version: 1.0.0 (01/09/2009)
* Copyright (c) 2009 jQueryGlobe
* Licensed under the MIT License: http://en.wikipedia.org/wiki/MIT_License
* Requires: jQuery v1.3+
*/
;(function($) {
$.fn.featureList = function(options) {
var tabs = $(this);
var output = $(options.output);
new jQuery.featureList(tabs, output, options);
return this;
};
$.featureList = function(tabs, output, options)
{
function slide(nr) {
if (typeof nr == "undefined") {
nr = visible_item + 1;
nr = nr >= total_items ? 0 : nr;
}
tabs.removeClass('current').filter(":eq(" + nr + ")").addClass('current');
output.stop(true, true).filter(":visible").fadeOut();
output.filter(":eq(" + nr + ")").fadeIn(function() {
visible_item = nr;
});
$(tabs[(nr - 1 + total_items) % total_items]).parent().slideUp(500,function(){
var order = "";
for(var i = total_items; i > 0; i--)
{
var nextInd = ((nr - 1) + i) % total_items;
var tab = $(tabs[nextInd]);
if(i == total_items)
tab.parent().slideDown(500);
tab.parent().prependTo(tab.parent().parent());
order += nextInd + ", ";
}
});
}
var options = options || {};
var total_items = tabs.length;
var visible_item = options.start_item || 0;
options.pause_on_hover = options.pause_on_hover || true;
options.transition_interval = options.transition_interval || 2000;
output.hide().eq( visible_item ).show();
tabs.eq( visible_item ).addClass('current');
tabs.click(function() {
if ($(this).hasClass('current')) {
return false;
}
slide( tabs.index( this) );
});
if (options.transition_interval > 0) {
var timer = setInterval(function () {
slide();
}, options.transition_interval);
if (options.pause_on_hover) {
tabs.mouseenter(function() {
clearInterval( timer );
}).mouseleave(function() {
clearInterval( timer );
timer = setInterval(function () {
slide();
}, options.transition_interval);
});
}
}
};
})(jQuery);
To increase the height of the box simply change the height of div#feature_list and to add additional items simply add an additional li item in both the ul's within feature_list