JSFiddle - React, Tailwind, and code Playground
by kougiland
HTML
<div class="rotator">
<div class="ctr" data-bind="style:{width:width, height:height}">
<div class="images" data-bind="
template: {name:'imageTpl',
foreach:images,
beforeRemove : function(elem) {this.removeDecorator(elem)}.bind($data)}"></div>
<!-- ko if: loading -->
<div class="loading">
<img src="http://pshabalin.files.wordpress.com/2013/01/loading.gif"/>
</div>
<!-- /ko -->
</div>
<div class="controls" data-bind="template: { name: 'controlTpl', foreach: imageViewModels}"></div>
</div>
</body>
<script id="imageTpl" type="text/html"><img data-bind="attr : {src : url}"/></script>
<script id="controlTpl" type="text/html">
<span data-bind="css : {active : active()}, click : $parent.onCtrlClick.bind($parent)"></span>
</script>
CSS
.rotator {
}
.ctr {
overflow: hidden;
border-radius: 2px;
-webkit-box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.2);
-moz-box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.2);
box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.2);
border: 1px solid #b6b6b6;
border-color: rgba(0, 0, 0, 0.2);
margin: 5px auto;
position: relative;
}
.rotator .images {
position: absolute;
overflow: hidden;
width: 100%;
height: 100%;
}
.rotator .images img {
position: absolute;
text-align: center;
display: block;
}
.loading {
position: absolute;
width: 100%;
height: 100%;
background: white;
}
.loading img {
position: absolute;
left: 48%;
top:45%;
}
.controls {
width: 100%;
text-align: center;
margin: 10px auto;
}
.controls span {
display: inline-block;
height: 12px;
width: 12px;
box-sizing: border-box;
background-color: rgba(0, 0, 0, 0.02);
border: 1px solid rgba(0, 0, 0, 0.2);
border-radius: 7px;
margin: 0 5px;
cursor: pointer;
box-shadow: 0px 2px 3px 0px rgba(0, 0, 0, 0.08) inset;
-webkit-transition: all 400ms;
transition: all 400ms;
}
.controls span.active {
cursor: default;
background-color: rgba(0, 0, 0, 0.4);
border: none; box-shadow: 0px -1px 1px 0px rgba(0, 0, 0, 0.35) inset;
}
JavaScript
var images = ['http://pshabalin.files.wordpress.com/2013/01/yellowstone-77.png', 'http://pshabalin.files.wordpress.com/2013/01/yellowstone-58.png', 'http://pshabalin.files.wordpress.com/2013/01/img_1082.png', 'http://pshabalin.files.wordpress.com/2013/01/dscn2295.png', 'http://pshabalin.files.wordpress.com/2013/01/img_1082.png', 'http://pshabalin.files.wordpress.com/2013/01/dscn2295.png', 'http://pshabalin.files.wordpress.com/2013/01/img_1082.png', 'http://pshabalin.files.wordpress.com/2013/01/dscn2295.png'];
var ImageRotator = function (options) {
this.width = options.width + 'px';
this.height = options.height + 'px';
this.imageUrls = options.images;
this.interval = options.interval;
this.transition = options.transition;
this.loading = ko.observable(true);
this.imageViewModels = [];
options.images.forEach(function (image) {
var imageViewModel = {url:image, active:ko.observable(false)};
this.imageViewModels.push(imageViewModel);
}.bind(this));
this.imageViewModels[0].active(true);
this.images = ko.observableArray();
this.jsInt = setInterval(this.nextImage.bind(this), this.interval);
this.loadFirstImage();
};
ImageRotator.prototype.nextImage = function () {
this.images.valueWillMutate();
var top = this.images.pop();
var ind = this.imageViewModels.indexOf(top);
var nextInd = (ind + 2) % this.imageViewModels.length;
var next = this.imageViewModels[nextInd];
this.images.unshift(next);
top.active(false);
this.images()[1].active(true);
this.images.valueHasMutated();
};
ImageRotator.prototype.onCtrlClick = function (imageVM) {
if (imageVM == this.images()[1]) {
return;
}
clearInterval(this.jsInt);
var top = this.images.pop();
this.images()[0] = imageVM;
var ind = this.imageViewModels.indexOf(imageVM);
var nextInd = (ind + 1) % this.imageViewModels.length;
var next = this.imageViewModels[nextInd];
...