I already tried to swap the functions on owl.carousel.js but it only works when the mouse moves.
var Autoplay = function(scope) {
this.core = scope;
this.core.options = $.extend({}, Autoplay.Defaults, this.core.options);
this.handlers = {
'translated.owl.carousel refreshed.owl.carousel': $.proxy(function() {
this.autoplay();
}, this),
'play.owl.autoplay': $.proxy(function(e, t, s) {
this.play(t, s);
}, this),
'stop.owl.autoplay': $.proxy(function() {
this.stop();
}, this),
'mouseover.owl.autoplay': $.proxy(function() {
if (this.core.settings.autoplayHoverPause) {
this.pause();
}
}, this),
'mouseleave.owl.autoplay': $.proxy(function() {
if (this.core.settings.autoplayHoverPause) {
this.autoplay();
}
}, this)
};
this.core.$element.on(this.handlers);};
Any idea how to make the slideshow work when mouse on top of the image?
When i had this problem, i used this code:
$('.owl-carousel .owl-dot').hover(function() {
$(this).click();
},
function() {}
);
and here my css for dots:
.owl-dot{
position: relative;
padding: 0;
height: 3px;
margin: 0;
float: left;
}
.owl-dot:before{
content: "";
position: absolute;
top: -168px; // the height of image
height: 168px; // the height of image
width: 100%;
left: 0;
z-index: 0;
}
when you will make hover to dots the image will be changing, that's all !!!
Related
After toying about with timers and intervals I have come to a solution that works to my satisfaction.
See relevant jsFiddle or code below:
HTML:
<div id="foo">irrelevant content</div>
javascript( with jQuery):
var post_array = [ "abc", "123", "xyz" ];
var class_array = [ "red", "blue", "green" ];
var interval = 2000;
var i = 0;
var max = post_array.length;
var id ="#foo";
$(id).html(post_array[0]);
$(id).removeClass().addClass(class_array[0]);
setInterval( function(){
++i;
$(id).fadeOut("slow", function() {
$(id).html(post_array[i%max]).fadeIn("slow");
$(id).removeClass().addClass(class_array[i%max]);
});
}, interval);
Now I wonder what the best way to add two side arrows that allow me to go back and fort would be.
should I have written the relevant code in a named function so I can call it and pass an index parameter when the button is pressed? ( how do i act on the same index variable in that case? )
What's the best practice for button overlays?
Help!
Thanks in advance
Carousels should be modular, reusable and extendable. Don't copy paste JS code when in need to add another Carousel into your DOM.
In order to create PREV / NEXT buttons you'll also need a method to stop your interval: stop
When you hover over your Carousel, you'll need to pause the autoplay to prevent a really bad User Experience (UX)
Don't animate using jQuery. Animate by simply assigning an is-active class to the current index slide, and use CSS to do whatever you want with that class.
Use a variable index (start with 0) to keep track of the current slide index
You Might Not Need jQuery
Aim to create a class instance using the sugary class or the proper prototype syntax - that can be used like:
const myCarousel = new Carousel({
target: "#carousel-one",
slides: [
{
title: "This is slide one",
image: "images/one.jpg"
},
{
title: "This is slide two! Yey.",
image: "images/two.jpg"
}
]
});
So basically, you'll need a constructor that has those methods:
Method
Description
anim()
Fix index if exceeds slides or is negative and animate to new index
prev()
Decrement index and trigger anim()
next()
Increment index and trigger anim()
stop()
Clear loop interval (On mouseenter)
play()
Start loop (Triggers next() every pause milliseconds)
Simple JavaScript carousel example
class Carousel {
constructor(options) {
Object.assign(this, {
slides: [],
index: 0,
pause: 4000, // Pause between slides
EL: document.querySelector(options.target || "#Carousel"),
autoplay: true,
}, options);
this.total = this.slides.length;
this.EL_area = this.EL.querySelector(".Carousel-area");
this.EL_prev = this.EL.querySelector(".Carousel-prev");
this.EL_next = this.EL.querySelector(".Carousel-next");
const NewEL = (tag, prop) => Object.assign(document.createElement(tag), prop);
// Preload images
this.ELs_items = this.slides.reduce((DF, item) => {
const EL_slide = NewEL("div", {
className: "Carousel-slide"
});
const EL_image = NewEL("img", {
className: "Carousel-image",
src: item.image,
alt: item.title
});
const EL_content = NewEL("div", {
className: "Carousel-title",
textContent: item.title
});
EL_slide.append(EL_image, EL_content);
DF.push(EL_slide);
return DF;
}, []);
this.EL_area.append(...this.ELs_items);
// Events
this.EL_prev.addEventListener("click", () => this.prev());
this.EL_next.addEventListener("click", () => this.next());
this.EL.addEventListener("mouseenter", () => this.stop());
this.EL.addEventListener("mouseleave", () => this.play());
// Init
this.anim();
this.play();
}
// Methods:
anim() {
this.index = this.index < 0 ? this.total - 1 : this.index >= this.total ? 0 : this.index;
this.ELs_items.forEach((EL, i) => EL.classList.toggle("is-active", i === this.index));
}
prev() {
this.index -= 1;
this.anim();
}
next() {
this.index += 1;
this.anim();
}
stop() {
clearInterval(this.itv);
}
play() {
if (this.autoplay) this.itv = setInterval(() => this.next(), this.pause);
}
}
// Use like:
new Carousel({
target: "#carousel-one",
slides: [{
title: "We're part of nature",
image: "https://picsum.photos/id/10/400/300"
},
{
title: "Remember to read and learn",
image: "https://picsum.photos/id/24/400/300"
},
{
title: "Up for a coffee?",
image: "https://picsum.photos/id/30/400/300"
},
]
});
/* CAROUSEL */
.Carousel {
position: relative;
height: 300px;
max-height: 100vh;
}
.Carousel-slide {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
transition: opacity 0.5s; /* DESIRED SLIDE TRANSITIONS */
opacity: 0; /* INACTIVE SLIDE*/
}
.Carousel-slide.is-active { /* ACTIVE SLIDE! */
opacity: 1;
z-index: 1;
}
.Carousel-prev,
.Carousel-next {
position: absolute;
z-index: 2;
top: 50%;
transform: translateY(-50%);
user-select: none; /* Prevent highlight */
}
.Carousel-prev {
left: 1em;
}
.Carousel-next{
right: 1em;
}
.Carousel-image {
position: absolute;
width: 100%;
height: 100%;
object-fit: cover;
}
.Carousel-title {
position: absolute;
width: 100%;
height: 100%;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
font-size: 3em;
}
<div class="Carousel" id="carousel-one">
<div class="Carousel-area"></div>
<button class="Carousel-prev" type="button" aria-label="Previous slide">←</button>
<button class="Carousel-next" type="button" aria-label="Next slide">→</button>
<div class="Carousel-desc"></div>
</div>
With the above code you can have an unlimited number of carousels on a single page given every one has a different target ID.
PS: Alternatively, if your code keeps track of the direction for the prev / next, the logic to increment/decrement/loopback the current index can be also written as (pseudocode ahead!):
C = (is_next ? ++C : --C) < 0 ? T-1 : C%T;
where C is the current index, T is the total number of slides, and is_next is a boolean that is true when the direction is Next.
I've made a simple bar chart plugin which takes some settings and data and displays it as a percentage, it's working perfectly fine in all browsers except IE9-10.
The chart still displays fine yet there is a weird 'jump' once each of the bars have finished animating where the table seems to gain additional height. I've measured the height of the bars in the chart in browsers where it's working fine and there appears to be an additional ~50px height being added in browsers where the weird 'jump' effect occurs.
Here is the relevant CSS:
#barchart {
text-align: center;
}
.bar {
margin-right: 10px;
position: relative;
bottom: 0;
overflow: hidden;
padding-top: 50px;
height: 100%;
}
.bar .label {
text-align: center;
width: inherit;
margin: 0 auto 20px auto;
width: 116px;
}
.bar__value {
height: 0%;
background-repeat: repeat-y;
background-position: top center;
margin: 0 5px;
}
And here is the JS:
var Crafted = (function(c) {
return c;
})(Crafted || {});
(function($, c) {
c.BarChart = (function() {
var barChart = function(target, options, data) {
this.target = target;
this.ChartItem(options);
this.data = data;
this.create();
};
barChart.prototype.ChartItem = function(options) {
var settings = $.extend({
width: '100%',
height: '500px',
usePercentSymbol: false,
delay: 1000,
animSpeed: 1000,
chartImage: '',
chartBgColour: '#CCCCCC'
}, options);
this.width = settings.width;
this.height = settings.height;
this.usePercentSymbol = settings.usePercentSymbol;
this.delay = settings.delay;
this.animSpeed = settings.animSpeed;
this.chartImage = settings.chartImage;
this.chartBgColour = settings.chartBgColour;
return this;
};
barChart.prototype.create = function() {
var _self = this;
if (!_self.target) {
console.error('Error: BarChart \'target\' must be specified');
return;
}
if (!_self.data) {
console.error('Error: BarChart \'data\' must be provided');
return;
}
var $barChart = $('<table></table>').attr('id', 'barchart');
var $charts = $('<tr></tr>').addClass('data-row');
$charts.appendTo($barChart);
$barChart.appendTo(_self.target);
$barChart.attr('width', _self.width)
.attr('height', _self.height);
$.each(_self.data, function(index, value) {
var $chart = $('<td></td>')
.addClass('bar')
.attr('valign', 'bottom')
.attr('data-percent', value.percent);
$chart.appendTo($charts);
var $chartLabel = $('<div></div>').addClass('label');
$chartLabel.appendTo($chart);
var $chartValue = $('<div></div>').addClass('label__percent').text(_self.usePercentSymbol ? '0%' : 0);
$chartValue.appendTo($chartLabel);
var $chartTitle = $('<div></div>').addClass('label__title').text(value.label);
$chartTitle.appendTo($chartLabel);
var $barValue = $('<div></div>').addClass('bar__value');
var barStyle = _self.chartImage ?
'background-image:url(\'' + _self.chartImage + '\');' :
'background-color:' + _self.chartBgColour
$barValue.attr('style', barStyle);
$barValue.appendTo($chart);
});
setTimeout(function() {
$('.bar').each(function() {
var percentage = $(this).attr('data-percent');
var $percentLbl = $(this).find('.label__percent');
$(this).children('.bar__value').animate({
height: percentage + '%'
}, _self.animSpeed);
$({
countNum: 0
}).animate({
countNum: percentage
}, {
duration: _self.animSpeed,
easing: 'linear',
progress: function() {
var currentValue = Math.floor(this.countNum);
$percentLbl.text(_self.usePercentSymbol ? currentValue + '%' : currentValue);
}
});
});
}, _self.delay);
};
return barChart;
})();
})(jQuery, Crafted);
$(function() {
(function(c) {
var settings = {
width: '800px',
height: '400px',
usePercentSymbol: true,
delay: 200,
animSpeed: 1000,
chartImage: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/662693/chimney.svg'
};
var data = [{
label: 'MANCHESTER',
percent: 78
}, {
label: 'BIRMINGHAM',
percent: 69
}, {
label: 'LONDON',
percent: 94
}, {
label: 'CARDIFF',
percent: 39
}, {
label: 'GLASGOW',
percent: 54
}, {
label: 'BELFAST',
percent: 35
}]
var barChart = new c.BarChart('#barChart', settings, data);
})(Crafted);
});
I have a JsFiddle that demonstrates the problem. If you load this in IE9/10 (you can use the browser emulator in IE dev tools - F12) you will see the strange effect I'm talking about. This doesn't occur in IE11/Edge etc...
Could it be due to the padding top applied to the <td> elements? This is used to give enough spacing for each chart label to prevent them from being cut off.
try with this css modification to bar class
.bar {
margin-right: 10px;
position: relative;
bottom: 0;
overflow: hidden;
padding-top: 50px;
height: 75%;
}
seems it works either on ie9/10 and chrome
I am writing a simple jQuery plugin for my purpose, which:
creates a background div (for blocking purposes, like a modal dialog). (referenced with backDiv)
shows that background.
shows $(this).
removes background and hides $(this) when background clicked.
I am able to do all of these except 4th one: As I can't save a reference to the background div, I cannot get it back and remove it.
I tried $(this).data('backDiv',backDiv); and $(this)[0].backDiv = backDiv;
I know that there are various plugins that does this including the jQuery's own dialog function, but I want to create my own version.
I cannot keep this variable globally, so, how can I keep a reference to backDiv in a jQuery object, (or DOM object?) if that's even possible at all?
update: I allow multiple of these elements show on top of each other: Nested modal dialogs.
update-2:
(function($) {
$.fn.showModal = function() {
var backDiv = $('<div style="width: 100%; height: 100%; background-color: rgba(55, 55, 55, 0.5); position:absolute;top:0px;left:0px;">This is backDiv</div>');
$(this).data('backDiv', backDiv);
$('body').append(backDiv);
//TODO: bringToFront(backDiv);
$(this).show();
//TODO: bringToFront($(this);
var thisRef = $(this);
backDiv.click(function() {
thisRef.closeModal();
});
return $(this);
};
$.fn.closeModal = function() {
//PROBLEM (null): var backDiv = $(this).data('backDiv');
//backDiv.remove();
$(this).data('backDiv', '');
$(this).hide();
}
}(jQuery));
$(document).ready(function() {
$('#a').showModal();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="a" style="display:none;z-Index:2;background:red; width: 100px; height:50px;position:absolute"></div>
I suggest you to work in terms of complex dom objects, something similar angular directives, basically, you have to work with components that are represented in the dom as Group of Objects.
So, following what I'm saying, your modal component should be something like that:
var Modal = (function($) {
var tpl = '<div style="display:none;" class="modal"><div class="modal-backdrop"></div><div class="modal-content"></div></div>';
function Modal(container) {
var self = this;
this.container = $(container || 'body');
this.tpl = $(tpl).appendTo(this.container);
this.content = $('.modal-content', this.tpl);
this.backdrop = $('.modal-backdrop', this.tpl);
this.isOpened = false;
this.ANIMATION_DURATION = 500;
this.backdrop.click(function(e) { self.toggle(e) });
}
Modal.prototype.show = function(cb) {
var self = this;
cb = $.isFunction(cb) ? cb : $.noop;
this.tpl.fadeIn(this.ANIMATION_DURATION, function() {
self.isOpened = true;
cb();
});
return this;
};
Modal.prototype.hide = function(cb) {
var self = this;
cb = $.isFunction(cb) ? cb : $.noop;
this.tpl.fadeOut(this.ANIMATION_DURATION, function() {
self.isOpened = false;
cb();
});
return this;
};
Modal.prototype.toggle = function() {
if(this.isOpened) {
return this.hide();
}
return this.show();
};
Modal.prototype.setContent = function(content) {
this.content.html($('<div />').append(content).html());
return this;
};
return Modal;
})(window.jQuery);
function ExampleCtrl($) {
var modal = new Modal();
modal.setContent('<h1>Hello World</h1>');
$('#test').click(function() {
modal.show();
});
}
window.jQuery(document).ready(ExampleCtrl);
.modal {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.modal .modal-backdrop {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: rgba(0, 0, 0, .8);
}
.modal .modal-content {
width: 300px;
height: 150px;
background: #fff;
border: 1px solid yellow;
position: absolute;
left: 50%;
top: 50%;
margin-left: -150px;
margin-top: -75px;
line-height: 150px;
text-align: center;
}
h1 {
line-height: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="test">Test Modal</button>
Add data-backDiv="" into you dynamic modal div
Change below
var backDiv = $('<div data-backDiv="" style="width: 100%; height: 100%; background-color: rgba(55, 55, 55, 0.5); position:absolute;top:0px;left:0px;">This is backDiv</div>');
In order to retrive data attribute value using JQuery use following code
Syntax
$('selector').data('data-KeyName');
Example
1. $(this).data('backDiv'); // use to retrive value or
2. var temp=$(this).data('backDiv'); // use to retrive value and assign into variable
Have worked out a solution, see the bottom!
I'm experimenting with a responsive carousel (fluid). I have elements stacked on top of each other so that the width can be fluid depending on the width of the parent. The issue is I need the parent to have overflow hidden which is not possible with children that are absolute positioned.
Tip on cleaning up the JS are appreciated too!
Does anyone have any ideas how to improve this or alternatives? Heres the fiddle: http://jsfiddle.net/j35fy/5/
.carousel-wrap {
position: relative;
}
.carousel-item {
position: absolute;
top: 0;
}
$.fn.mwCarousel = function(options) {
//Default settings.
var settings = $.extend({
changeWait: 3000,
changeSpeed: 800,
reveal: false,
slide: true,
autoRotate: true
}, options );
var CHANGE_WAIT = settings.changeWait;
var CHANGE_SPEED = settings.changeSpeed;
var REVEAL = settings.reveal;
var SLIDE = settings.slide;
var AUTO_ROTATE = settings.autoRotate;
var $carouselWrap = $(this);
var SLIDE_COUNT = $carouselWrap.find('.carousel-item').length;
var rotateTimeout;
if (AUTO_ROTATE) {
rotateTimeout = setTimeout(function(){
rotateCarousel(SLIDE_COUNT-1);
}, CHANGE_WAIT);
}
function rotateCarousel(slide) {
if (slide === 0) {
slide = SLIDE_COUNT-1;
rotateTimeout = setTimeout(function(){
$('.carousel-item').css('margin', 0);
$('.carousel-item').show();
}, CHANGE_WAIT);
if (REVEAL) {
$($carouselWrap.find('.carousel-item')[slide]).slideToggle(CHANGE_SPEED);
} else if (SLIDE) {
var carouselItem = $($carouselWrap.find('.carousel-item')[slide]);
carouselItem.show();
var itemWidth = carouselItem.width();
carouselItem.animate({margin: 0}, CHANGE_SPEED);
} else {
$($carouselWrap.find('.carousel-item')[slide]).fadeIn(CHANGE_SPEED);
}
slide = slide+1;
} else {
if (REVEAL) {
$($carouselWrap.find('.carousel-item')[slide]).slideToggle(CHANGE_SPEED);
} else if (SLIDE) {
var carouselItem = $($carouselWrap.find('.carousel-item')[slide]);
var itemWidth = carouselItem.width();
carouselItem.animate({marginLeft: -itemWidth, marginRight: itemWidth}, CHANGE_SPEED);
} else {
$($carouselWrap.find('.carousel-item')[slide]).fadeOut(CHANGE_SPEED);
}
}
rotateTimeout = setTimeout(function(){
rotateCarousel(slide-1);
}, CHANGE_WAIT);
}
}
$('.carousel-wrap').mwCarousel();
Solution
The first slide actually never moves (last one visible) so that one is set to position: static and all works nicely.
I think by just changing your CSS you're actually there:
.carousel-wrap {
position: relative;
overflow:hidden;
height:80%;
width:90%;
}
Demo: http://jsfiddle.net/robschmuecker/j35fy/2/
Discovered the solution is in fact simple, as the first slide in the DOM (the last you see) never actually moves itself I can set that one slide to be position: static and thus the carousel wrap will set it's height accordingly.
http://jsfiddle.net/j35fy/7/
.container {
background: aliceblue;
padding: 3em;
}
.carousel-wrap {
position: relative;
overflow:hidden;
}
.carousel-item:first-child {
position:static;
}
.carousel-item {
position: absolute;
top: 0;
width: 100%;
}
img {
width: 100%;
}
I'm trying to create a dialog window using the following CSS:
#blackOverlay {
display: block;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #000000;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";
filter: alpha(opacity=80);
-moz-opacity: 0.8;
-khtml-opacity: 0.8;
opacity: 0.8;
z-index: 1001;
}
#whiteOverlay {
display: block;
position: absolute;
top: 10%;
left: 10%;
width: 80%;
height: 80%;
z-index:2002;
overflow: auto;
background: #c4e982;
}
and the following JS:
var div = $("<div id='blackOverlay'></div");
$("body").prepend(div);
var div = $("<div id='whiteOverlay'></div");
div.html("Loading......");
var u = "myurl?function=example";
div.load(u);
$("body").prepend(div);
This works correctly in Firefox, Safari, Chrome and Opera.
Unfortunately it fails in IE, at least on version 8.0. The color/opacity is only applied to body and NOT on other DIV's. Instead of "hidding" everything behind the blackOverlay, everything (links, buttons, input fields, ...) is still usable although the loaded content is displayed correctly (in front, center of screen).
Any help is appreciated!
Thank you jduren for pointing me in the right direction. After attempting to handle it in similar way as described here I came up with the following workaround:
function shime() {
jQuery.each(jQuery.browser, function(i) {
if($.browser.msie){
$('div').each(function() {
$(this).addClass("shine");
});
}
});
}
function unshime() {
jQuery.each(jQuery.browser, function(i) {
if($.browser.msie){
$(".shine").each(function() {
$(this).removeClass("shine");
});
}
});
}
And the following CSS:
div.shine {
display: none;
}
I know that it's not the best solution, but I'm getting tired of running in circles due to IE "features".
You need to create what's called an iFrame shim. IE paints controls over everything that isn't windowed so you won't be able to handle this by CSS/HTML hacks alone.
Here is a quick overview of Iframe Shimming http://www.macridesweb.com/oltest/IframeShim.html
Also, the Mootools More library includes an iFrame shim Feature http://mootools.net/docs/more/Utilities/IframeShim as do most popular javascript frameworks that create overlayed UI elements.
This is the IFrame Shim class from mootools more library to give you an idea of what's involved, don't use this as it depends on other Mootoosl classes.
var IframeShim = new Class({
Implements: [Options, Events, Class.Occlude],
options: {
className: 'iframeShim',
src: 'javascript:false;document.write("");',
display: false,
zIndex: null,
margin: 0,
offset: {x: 0, y: 0},
browsers: (Browser.Engine.trident4 || (Browser.Engine.gecko && !Browser.Engine.gecko19 && Browser.Platform.mac))
},
property: 'IframeShim',
initialize: function(element, options){
this.element = document.id(element);
if (this.occlude()) return this.occluded;
this.setOptions(options);
this.makeShim();
return this;
},
makeShim: function(){
if(this.options.browsers){
var zIndex = this.element.getStyle('zIndex').toInt();
if (!zIndex){
zIndex = 1;
var pos = this.element.getStyle('position');
if (pos == 'static' || !pos) this.element.setStyle('position', 'relative');
this.element.setStyle('zIndex', zIndex);
}
zIndex = ($chk(this.options.zIndex) && zIndex > this.options.zIndex) ? this.options.zIndex : zIndex - 1;
if (zIndex < 0) zIndex = 1;
this.shim = new Element('iframe', {
src: this.options.src,
scrolling: 'no',
frameborder: 0,
styles: {
zIndex: zIndex,
position: 'absolute',
border: 'none',
filter: 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)'
},
'class': this.options.className
}).store('IframeShim', this);
var inject = (function(){
this.shim.inject(this.element, 'after');
this[this.options.display ? 'show' : 'hide']();
this.fireEvent('inject');
}).bind(this);
if (!IframeShim.ready) window.addEvent('load', inject);
else inject();
} else {
this.position = this.hide = this.show = this.dispose = $lambda(this);
}
},
position: function(){
if (!IframeShim.ready || !this.shim) return this;
var size = this.element.measure(function(){
return this.getSize();
});
if (this.options.margin != undefined){
size.x = size.x - (this.options.margin * 2);
size.y = size.y - (this.options.margin * 2);
this.options.offset.x += this.options.margin;
this.options.offset.y += this.options.margin;
}
this.shim.set({width: size.x, height: size.y}).position({
relativeTo: this.element,
offset: this.options.offset
});
return this;
},
hide: function(){
if (this.shim) this.shim.setStyle('display', 'none');
return this;
},
show: function(){
if (this.shim) this.shim.setStyle('display', 'block');
return this.position();
},
dispose: function(){
if (this.shim) this.shim.dispose();
return this;
},
destroy: function(){
if (this.shim) this.shim.destroy();
return this;
}
});
window.addEvent('load', function(){
IframeShim.ready = true;
});