Building a Bootstrap template for a responsive site. It needs to show a simple horizontal navbar on desktop and tablet, then go to offcanvas slide-in on phones. Found an example by Phil Hughes (iamphill) on Github. As I adapted this, the dropdown menu items stopped working. When I click on either of the two dropdowns nothing happens. No errors in Chrome Inspector. Validating HTML, CSS and JS does not reveal anything. The bug is either too obvious or too subtle.
! function(t) {
"use strict";
"function" == typeof define && define.amd ? define(["jquery"], t) : "object" == typeof exports ? module.exports = t(require("jquery")) : t(jQuery)
}(function(t) {
"use strict";
function e(e) {
var o = e.attr("data-target");
o || (o = e.attr("href"), o = o && /#[A-Za-z]/.test(o) && o.replace(/.*(?=#[^\s]*$)/, ""));
var n = o && t(o);
return n && n.length ? n : e.parent()
}
function o(o) {
o && 3 === o.which || (t(r).remove(), t(a).each(function() {
var n = t(this),
r = e(n),
a = {
relatedTarget: this
};
r.hasClass("open") && (o && "click" == o.type && /input|textarea/i.test(o.target.tagName) && t.contains(r[0], o.target) || (r.trigger(o = t.Event("hide.bs.dropdown", a)), o.isDefaultPrevented() || (n.attr("aria-expanded", "false"), r.removeClass("open").trigger(t.Event("hidden.bs.dropdown", a)))))
}))
}
function n(e) {
return this.each(function() {
var o = t(this),
n = o.data("bs.dropdown");
n || o.data("bs.dropdown", n = new i(this)), "string" == typeof e && n[e].call(o)
})
}
var r = ".dropdown-backdrop",
a = '[data-toggle="dropdown"]',
d = ".drawer-nav",
i = function(e) {
t(e).on("click.bs.dropdown", this.toggle)
};
i.VERSION = "3.3.5", i.prototype.toggle = function(n) {
var r = t(this);
if (!r.is(".disabled, :disabled")) {
var a = e(r),
i = a.hasClass("open");
if (o(), !i) {
"ontouchstart" in document.documentElement && !a.closest(d).length && t(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(t(this)).on("click", o);
var s = {
relatedTarget: this
};
if (a.trigger(n = t.Event("show.bs.dropdown", s)), n.isDefaultPrevented()) return;
r.trigger("focus").attr("aria-expanded", "true"), a.toggleClass("open").trigger(t.Event("shown.bs.dropdown", s))
}
return !1
}
}, i.prototype.keydown = function(o) {
if (/(38|40|27|32)/.test(o.which) && !/input|textarea/i.test(o.target.tagName)) {
var n = t(this);
if (o.preventDefault(), o.stopPropagation(), !n.is(".disabled, :disabled")) {
var r = e(n),
d = r.hasClass("open");
if (!d && 27 != o.which || d && 27 == o.which) return 27 == o.which && r.find(a).trigger("focus"), n.trigger("click");
var i = " li:not(.disabled):visible a",
s = r.find(".dropdown-menu" + i);
if (s.length) {
var p = s.index(o.target);
38 == o.which && p > 0 && p--, 40 == o.which && p < s.length - 1 && p++, ~p || (p = 0), s.eq(p).trigger("focus")
}
}
}
};
var s = t.fn.dropdown;
t.fn.dropdown = n, t.fn.dropdown.Constructor = i, t.fn.dropdown.noConflict = function() {
return t.fn.dropdown = s, this
}, t(document).on("click.bs.dropdown.data-api", o).on("click.bs.dropdown.data-api", ".dropdown form", function(t) {
t.stopPropagation()
}).on("click.bs.dropdown.data-api", a, i.prototype.toggle).on("keydown.bs.dropdown.data-api", a, i.prototype.keydown).on("keydown.bs.dropdown.data-api", ".dropdown-menu", i.prototype.keydown)
});
// and now js for offcanvas
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
(function($, window) {
var Offcanvas, OffcanvasDropdown, OffcanvasTouch, transformCheck;
OffcanvasDropdown = (function() {
function OffcanvasDropdown(element) {
this.element = element;
this._clickEvent = bind(this._clickEvent, this);
this.element = $(this.element);
this.nav = this.element.closest(".nav");
this.dropdown = this.element.parent().find(".dropdown-menu");
this.element.on('click', this._clickEvent);
this.nav.closest('.navbar-offcanvas').on('click', (function(_this) {
return function() {
if (_this.dropdown.is('.shown')) {
return _this.dropdown.removeClass('shown').closest('.active').removeClass('active');
}
};
})(this));
}
OffcanvasDropdown.prototype._clickEvent = function(e) {
if (!this.dropdown.hasClass('shown')) {
e.preventDefault();
}
e.stopPropagation();
$('.dropdown-toggle').not(this.element).closest('.active').removeClass('active').find('.dropdown-menu').removeClass('shown');
this.dropdown.toggleClass("shown");
return this.element.parent().toggleClass('active');
};
return OffcanvasDropdown;
})();
OffcanvasTouch = (function() {
function OffcanvasTouch(button, element, location, offcanvas) {
this.button = button;
this.element = element;
this.location = location;
this.offcanvas = offcanvas;
this._getFade = bind(this._getFade, this);
this._getCss = bind(this._getCss, this);
this._touchEnd = bind(this._touchEnd, this);
this._touchMove = bind(this._touchMove, this);
this._touchStart = bind(this._touchStart, this);
this.endThreshold = 130;
this.startThreshold = this.element.hasClass('navbar-offcanvas-right') ? $("body").outerWidth() - 60 : 20;
this.maxStartThreshold = this.element.hasClass('navbar-offcanvas-right') ? $("body").outerWidth() - 20 : 60;
this.currentX = 0;
this.fade = this.element.hasClass('navbar-offcanvas-fade') ? true : false;
$(document).on("touchstart", this._touchStart);
$(document).on("touchmove", this._touchMove);
$(document).on("touchend", this._touchEnd);
}
OffcanvasTouch.prototype._touchStart = function(e) {
this.startX = e.originalEvent.touches[0].pageX;
if (this.element.is('.in')) {
return this.element.height($(window).outerHeight());
}
};
OffcanvasTouch.prototype._touchMove = function(e) {
var x;
if ($(e.target).parents('.navbar-offcanvas').length > 0) {
return true;
}
if (this.startX > this.startThreshold && this.startX < this.maxStartThreshold) {
e.preventDefault();
x = e.originalEvent.touches[0].pageX - this.startX;
x = this.element.hasClass('navbar-offcanvas-right') ? -x : x;
if (Math.abs(x) < this.element.outerWidth()) {
this.element.css(this._getCss(x));
return this.element.css(this._getFade(x));
}
} else if (this.element.hasClass('in')) {
e.preventDefault();
x = e.originalEvent.touches[0].pageX + (this.currentX - this.startX);
x = this.element.hasClass('navbar-offcanvas-right') ? -x : x;
if (Math.abs(x) < this.element.outerWidth()) {
this.element.css(this._getCss(x));
return this.element.css(this._getFade(x));
}
}
};
OffcanvasTouch.prototype._touchEnd = function(e) {
var end, sendEvents, x;
if ($(e.target).parents('.navbar-offcanvas').length > 0) {
return true;
}
sendEvents = false;
x = e.originalEvent.changedTouches[0].pageX;
if (Math.abs(x) === this.startX) {
return;
}
end = this.element.hasClass('navbar-offcanvas-right') ? Math.abs(x) > (this.endThreshold + 50) : x < (this.endThreshold + 50);
if (this.element.hasClass('in') && end) {
this.currentX = 0;
this.element.removeClass('in').css(this._clearCss());
this.button.removeClass('is-open');
sendEvents = true;
} else if (Math.abs(x - this.startX) > this.endThreshold && this.startX > this.startThreshold && this.startX < this.maxStartThreshold) {
this.currentX = this.element.hasClass('navbar-offcanvas-right') ? -this.element.outerWidth() : this.element.outerWidth();
this.element.toggleClass('in').css(this._clearCss());
this.button.toggleClass('is-open');
sendEvents = true;
} else {
this.element.css(this._clearCss());
}
return this.offcanvas.bodyOverflow(sendEvents);
};
OffcanvasTouch.prototype._getCss = function(x) {
x = this.element.hasClass('navbar-offcanvas-right') ? -x : x;
return {
"-webkit-transform": "translate3d(" + x + "px, 0px, 0px)",
"-webkit-transition-duration": "0s",
"-moz-transform": "translate3d(" + x + "px, 0px, 0px)",
"-moz-transition": "0s",
"-o-transform": "translate3d(" + x + "px, 0px, 0px)",
"-o-transition": "0s",
"transform": "translate3d(" + x + "px, 0px, 0px)",
"transition": "0s"
};
};
OffcanvasTouch.prototype._getFade = function(x) {
if (this.fade) {
return {
"opacity": x / this.element.outerWidth()
};
} else {
return {};
}
};
OffcanvasTouch.prototype._clearCss = function() {
return {
"-webkit-transform": "",
"-webkit-transition-duration": "",
"-moz-transform": "",
"-moz-transition": "",
"-o-transform": "",
"-o-transition": "",
"transform": "",
"transition": "",
"opacity": ""
};
};
return OffcanvasTouch;
})();
window.Offcanvas = Offcanvas = (function() {
function Offcanvas(element) {
var t, target;
this.element = element;
this.bodyOverflow = bind(this.bodyOverflow, this);
this._sendEventsAfter = bind(this._sendEventsAfter, this);
this._sendEventsBefore = bind(this._sendEventsBefore, this);
this._documentClicked = bind(this._documentClicked, this);
this._close = bind(this._close, this);
this._open = bind(this._open, this);
this._clicked = bind(this._clicked, this);
this._navbarHeight = bind(this._navbarHeight, this);
target = this.element.attr('data-target') ? this.element.attr('data-target') : false;
if (target) {
this.target = $(target);
if (this.target.length && !this.target.hasClass('js-offcanvas-done')) {
this.element.addClass('js-offcanvas-has-events');
this.location = this.target.hasClass("navbar-offcanvas-right") ? "right" : "left";
this.target.addClass(transform ? "offcanvas-transform js-offcanvas-done" : "offcanvas-position js-offcanvas-done");
this.target.data('offcanvas', this);
this.element.on("click", this._clicked);
this.target.on('transitionend', (function(_this) {
return function() {
if (_this.target.is(':not(.in)')) {
return _this.target.height('');
}
};
})(this));
$(document).on("click", this._documentClicked);
if (this.target.hasClass('navbar-offcanvas-touch')) {
t = new OffcanvasTouch(this.element, this.target, this.location, this);
}
this.target.find(".dropdown-toggle").each(function() {
var d;
return d = new OffcanvasDropdown(this);
});
this.target.on('offcanvas.toggle', (function(_this) {
return function(e) {
return _this._clicked(e);
};
})(this));
this.target.on('offcanvas.close', (function(_this) {
return function(e) {
return _this._close(e);
};
})(this));
this.target.on('offcanvas.open', (function(_this) {
return function(e) {
return _this._open(e);
};
})(this));
}
} else {
console.warn('Offcanvas: `data-target` attribute must be present.');
}
}
Offcanvas.prototype._navbarHeight = function() {
if (this.target.is('.in')) {
return this.target.height($(window).outerHeight());
}
};
Offcanvas.prototype._clicked = function(e) {
e.preventDefault();
this._sendEventsBefore();
$(".navbar-offcanvas").not(this.target).trigger('offcanvas.close');
this.target.toggleClass('in');
this.element.toggleClass('is-open');
this._navbarHeight();
return this.bodyOverflow();
};
Offcanvas.prototype._open = function(e) {
e.preventDefault();
if (this.target.is('.in')) {
return;
}
this._sendEventsBefore();
this.target.addClass('in');
this.element.addClass('is-open');
this._navbarHeight();
return this.bodyOverflow();
};
Offcanvas.prototype._close = function(e) {
e.preventDefault();
if (this.target.is(':not(.in)')) {
return;
}
this._sendEventsBefore();
this.target.removeClass('in');
this.element.removeClass('is-open');
this._navbarHeight();
return this.bodyOverflow();
};
Offcanvas.prototype._documentClicked = function(e) {
var clickedEl;
clickedEl = $(e.target);
if (!clickedEl.hasClass('offcanvas-toggle') && clickedEl.parents('.offcanvas-toggle').length === 0 && clickedEl.parents('.navbar-offcanvas').length === 0 && !clickedEl.hasClass('navbar-offcanvas')) {
if (this.target.hasClass('in')) {
e.preventDefault();
this._sendEventsBefore();
this.target.removeClass('in');
this.element.removeClass('is-open');
this._navbarHeight();
return this.bodyOverflow();
}
}
};
Offcanvas.prototype._sendEventsBefore = function() {
if (this.target.hasClass('in')) {
return this.target.trigger('hide.bs.offcanvas');
} else {
return this.target.trigger('show.bs.offcanvas');
}
};
Offcanvas.prototype._sendEventsAfter = function() {
if (this.target.hasClass('in')) {
return this.target.trigger('shown.bs.offcanvas');
} else {
return this.target.trigger('hidden.bs.offcanvas');
}
};
Offcanvas.prototype.bodyOverflow = function(events) {
if (events === null) {
events = true;
}
if (this.target.is('.in')) {
$('body').addClass('offcanvas-stop-scrolling');
} else {
$('body').removeClass('offcanvas-stop-scrolling');
}
if (events) {
return this._sendEventsAfter();
}
};
return Offcanvas;
})();
transformCheck = (function(_this) {
return function() {
var asSupport, el, regex, translate3D;
el = document.createElement('div');
translate3D = "translate3d(0px, 0px, 0px)";
regex = /translate3d\(0px, 0px, 0px\)/g;
el.style.cssText = "-webkit-transform: " + translate3D + "; -moz-transform: " + translate3D + "; -o-transform: " + translate3D + "; transform: " + translate3D;
asSupport = el.style.cssText.match(regex);
return _this.transform = asSupport.length !== null;
};
})(this);
return $(function() {
transformCheck();
$('[data-toggle="offcanvas"]').each(function() {
var oc;
return oc = new Offcanvas($(this));
});
$(window).on('resize', function() {
$('.navbar-offcanvas.in').each(function() {
return $(this).height('').removeClass('in');
});
return $('.offcanvas-toggle').removeClass('is-open');
});
return $('.offcanvas-toggle').each(function() {
return $(this).on('click', function(e) {
var el, selector;
if (!$(this).hasClass('js-offcanvas-has-events')) {
selector = $(this).attr('data-target');
el = $(selector);
if (el) {
el.height('');
el.removeClass('in');
return $('body').css({
overflow: '',
position: ''
});
}
}
});
});
});
})(window.jQuery, window);
}).call(this);
/* CSS used here will be applied after bootstrap.css */
#media (max-width: 767px) {
.offcanvas-stop-scrolling {
height: 100%;
overflow: hidden; }
.navbar-default .navbar-offcanvas {
background-color: #f8f8f8; }
.navbar-inverse .navbar-offcanvas {
background-color: #222; }
.navbar-offcanvas {
position: fixed;
width: 100%;
max-width: 250px;
left: -250px;
top: 0;
padding-left: 15px;
padding-right: 15px;
z-index: 999;
overflow: scroll;
-webkit-overflow-scrolling: touch;
-webkit-transition: all 0.15s ease-in;
transition: all 0.15s ease-in; }
.navbar-offcanvas.in {
box-shadow: 0 0 20px rgba(0, 0, 0, 0.3); }
.navbar-offcanvas.navbar-offcanvas-fade {
opacity: 0; }
.navbar-offcanvas.navbar-offcanvas-fade.in {
opacity: 1; }
.navbar-offcanvas.offcanvas-transform.in {
-webkit-transform: translateX(250px);
transform: translateX(250px); }
.navbar-offcanvas.offcanvas-position.in {
left: 0; }
.navbar-offcanvas.navbar-offcanvas-right {
left: auto;
right: -250px; }
.navbar-offcanvas.navbar-offcanvas-right.offcanvas-transform.in {
-webkit-transform: translateX(-250px);
transform: translateX(-250px); }
.navbar-offcanvas.navbar-offcanvas-right.offcanvas-position.in {
left: auto;
right: 0; }
.navbar-offcanvas .dropdown.active .caret {
border-top: 0;
border-bottom: 4px solid; }
.navbar-offcanvas .dropdown-menu {
position: relative;
width: 100%;
border: inherit;
box-shadow: none;
-webkit-transition: height 0.15s ease-in;
transition: height 0.15s ease-in; }
.navbar-offcanvas .dropdown-menu.shown {
display: block;
margin-bottom: 10px; } }
.offcanvas-toggle .icon-bar {
background: #000;
-webkit-transition: all .25s ease-in-out;
transition: all .25s ease-in-out; }
.offcanvas-toggle.is-open .icon-bar:nth-child(1) {
-webkit-transform: rotate(45deg) translate(5px, 4px);
transform: rotate(45deg) translate(5px, 4px); }
.offcanvas-toggle.is-open .icon-bar:nth-child(2) {
opacity: 0; }
.offcanvas-toggle.is-open .icon-bar:nth-child(3) {
-webkit-transform: rotate(-45deg) translate(4px, -4px);
transform: rotate(-45deg) translate(4px, -4px); }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<body class="body-offcanvas">
<header class="clearfix">
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle offcanvas-toggle" data-toggle="offcanvas" data-target="#js-bootstrap-offcanvas">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Brandhere</a>
</div>
<div class="navbar-offcanvas navbar-offcanvas-touch" id="js-bootstrap-offcanvas">
<ul class="nav navbar-nav">
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">NUMBERS<span class="caret"></span></a>
<ul class="dropdown-menu">
<li>One</li>
<li>Two</li>
<li>Thirty-six</li>
<li>-7</li>
<li>Eighteen</li>
</ul>
</li>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">MUSIC<span class="caret"></span></a>
<ul class="dropdown-menu">
<li>BJ Cole</li>
<li>C. Debussy</li>
<li>Brian Eno</li>
<li>Robert Fripp</li>
<li>Skip James</li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<div class="row">
<div>
<h1>Page Title</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin feugiat hendrerit feugiat. In cursus nisl id arcu ullamcorper, eget euismod ante tincidunt. Aliquam tincidunt felis eget quam euismod cursus. Nam aliquet a tellus ut pretium. Pellentesque fermentum nulla tempus mauris sagittis, eget imperdiet quam tristique. Pellentesque quis mauris mauris. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent sodales turpis fringilla ligula rutrum, eget mattis justo bibendum. Integer imperdiet mi non cursus bibendum. Nullam vitae cursus justo. Integer quis elit sit amet arcu pellentesque sit amet a sapien. Aliquam tincidunt felis eget quam euismod cursus. Suspendisse lobortis ut elit vitae rhoncus. Ut tincidunt, ante eu egestas sodales, dui nulla aliquet mi, a eleifend lacus risus sit amet lacus.</p>
</div>
</div>
</div>
</body>
Here it is on Bootply http://www.bootply.com/ONyk2E5GWv
There are 2 things here:
1) You're using same class for dropdown-toggle for both Numbers as well as Music. Try to keep it unique like below -
<li class="dropdown numbers">
<a class="dropdown-toggle" data-toggle="numbers" href="#">NUMBERS<span class="caret"></span></a>
<ul class="dropdown-menu">
<li>One</li>
</ul>
</li>
<li class="dropdown music">
<a class="dropdown-toggle" data-toggle="music" href="#">MUSIC<span class="caret"></span></a>
<ul class="dropdown-menu">
<li>BJ Cole</li>
</ul>
</li>
2) You're using CSS Media Query max-width: 767px which means that this styling is applied only for screens whose width are less than 767 pixels, ideally Tablets and Mobile devices. Upon click of dropdown, on the dropdown-menu, 'shown' class is being added which will have the styling of displaying the list by changing the CSS attribute display from 'none' to 'block'
.navbar-offcanvas .dropdown-menu.shown {
display: block;
margin-bottom: 10px;
}
Related
I have an element bordered with an Svg:
.element-bordered-with-svg {
border-image-source: url('images/border.svg');
[....]
}
Inside the border.svg there is a CSS animation (defined in the <style> tag), like so:
<svg class="svg-frame-1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 337 198">
<style>
.svg-frame-1:hover > path {
animation-play-state: running;
}
path {
stroke:#BEA757;
fill-opacity:0;
stroke-width:1;
stroke-dasharray: 1948;
stroke-dashoffset:1948;
animation-name: dash1;
animation-duration: 2s;
animation-fill-mode: forwards;
animation-delay: 2s;
animation-play-state: paused;
}
#keyframes dash1 {
0% { stroke-dashoffset:1948;}
100%{stroke-dashoffset:0;}
}
</style>
[...]
</svg>
I would like to start the animation only when I hover the .element-bordered-with-svg element.
Of course, because it is not inlined, the <svg> knows nothing about the elements of the main DOM and vice versa.
Is there a possible solution, perhaps in JavaScript, to this problem?
EDITED: following the advice of #Danny '365CSI' Engelman in the comments I've tried with this solution (see the snippet):
function docReady(fn) {
// see if DOM is already available
if (
document.readyState === 'complete' ||
document.readyState === 'interactive'
) {
// call on next available tick
setTimeout(fn, 1);
} else {
document.addEventListener('DOMContentLoaded', fn);
}
}
function escapeRegExp(str) {
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1');
}
function replaceAll(str, find, replace) {
return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
}
function transformInDataUri(id) {
var svgText = new XMLSerializer().serializeToString(
document.getElementById(id),
);
var raw = svgText;
var encoded = raw.replace(/\s+/g, ' ');
// According to Taylor Hunt, lowercase gzips better ... my tiny test confirms this
encoded = replaceAll(encoded, '%', '%25');
encoded = replaceAll(encoded, '> <', '><'); // normalize spaces elements
encoded = replaceAll(encoded, '; }', ';}'); // normalize spaces CSS
encoded = replaceAll(encoded, '<', '%3c');
encoded = replaceAll(encoded, '>', '%3e');
encoded = replaceAll(encoded, '"', "'");
encoded = replaceAll(encoded, '#', '%23'); // needed for IE and Firefox
encoded = replaceAll(encoded, '{', '%7b');
encoded = replaceAll(encoded, '}', '%7d');
encoded = replaceAll(encoded, '|', '%7c');
encoded = replaceAll(encoded, '^', '%5e');
encoded = replaceAll(encoded, '`', '%60');
encoded = replaceAll(encoded, '#', '%40');
var uri = 'url("data:image/svg+xml;charset=UTF-8,' + encoded + '")';
return uri;
}
function getCurrentAnimatePropertyValue(el, propertyName) {
let value = getComputedStyle(el, null).getPropertyValue(propertyName);
return value;
}
function getTimer() {
console.log('ok')
let elapsedTime = 0;
let timer;
function start() {
timer = window.setInterval(function() {
elapsedTime += 100
console.log(elapsedTime)
}, 100)
}
function pause() {
window.clearInterval(timer)
console.log(elapsedTime)
return elapsedTime
}
function reset() {
window.clearInterval(timer)
elapsedTime = 0;
console.log(elapsedTime)
return elapsedTime
}
return {
start: start,
pause: pause,
reset: reset
}
}
function getUpdatedDurations(currentDurations, elapsedTime) {
let animationDurations = currentDurations; // '2s, 1s';
let values = animationDurations.replace(/\s/g, "").split(',').map(el => {
let finalEl = parseFloat(el.replace("s", "")) * 1000;
return finalEl;
})
let updatedValues = values.map(duration => duration - elapsedTime )
let updatedValuesAsString = updatedValues.map(duration => {
return (duration/1000).toString(10) + 's';
})
return updatedValuesAsString.toString()
}
// svg, [{ 'dash1': {'dash-offset': '1000px' }}, { 'fill': {'fill-opacity': 1 }}]
function changeAnimationStartKeyFrame(animations) {
for (let index = 0; index <document.styleSheets.length; index++) {
let stylesheet = document.styleSheets[index];
if(stylesheet['title'] === 'svg') {
animations.map(animation => {
let animationName = Object.keys(animation)[0];
let cssRules = stylesheet['cssRules']
let objectWithRules = animation[animationName];
let propertyName = Object.keys(objectWithRules)[0]
let updatedValue = objectWithRules[propertyName];
for (let index = 0; index < cssRules.length; index++) {
let cssRule = cssRules[index];
if(cssRule.type === 7 && cssRule.name === animationName) {
console.log(propertyName)
let CSSKeyframesRule = cssRule;
if(animationName === 'dash1') {
CSSKeyframesRule.deleteRule("0%");
CSSKeyframesRule.appendRule(`0% { ${propertyName}: ${updatedValue}; }`);
}
else {
CSSKeyframesRule.deleteRule("80%");
CSSKeyframesRule.appendRule(`80% { ${propertyName}: ${updatedValue}; }`);
}
}
}
})
}
console.log(stylesheet)
}
}
docReady(function () {
// charset reportedly not needed ... I need to test before implementing
console.log(Array.from(document.styleSheets))
var svgAsBorderSelector = 'svg-as-border';
var svg = document.getElementById(svgAsBorderSelector);
var svgAnimatedSelectors = '.path-1';
var svgElementsToAnimate = svg.querySelectorAll(svgAnimatedSelectors);
let divToBorderWithAnimatedSvg = document.querySelector('.frame-1');
divToBorderWithAnimatedSvg.style.borderImageSource = transformInDataUri(
svgAsBorderSelector,
);
let currentFillOpacity;
let currentStrokeDashOffset;
let currentStrokeDashArray;
let timer = getTimer(), elapsedTime;
divToBorderWithAnimatedSvg.addEventListener('mouseenter', (e) => {
for (var i = 0, max = svgElementsToAnimate.length; i < max; i++) {
let element = svgElementsToAnimate[i];
currentStrokeDashOffset = getCurrentAnimatePropertyValue(
element,
'stroke-dashoffset',
);
currentStrokeDashArray = getCurrentAnimatePropertyValue(
element,
'stroke-dasharray',
);
currentFillOpacity = getCurrentAnimatePropertyValue(
element,
'fill-opacity',
);
document.body.clientHeight
element.style.webkitAnimationName = 'dash1';
timer.start();
element.style.strokeDashoffset = currentStrokeDashOffset;
element.style.strokeDasharray = currentStrokeDashArray;
element.style.fillOpacity = currentFillOpacity;
element.style.animationPlayState = 'running, running';
}
divToBorderWithAnimatedSvg.style.borderImageSource = transformInDataUri(
svgAsBorderSelector,
);
});
divToBorderWithAnimatedSvg.addEventListener('mouseleave', (e) => {
for (var i = 0, max = svgElementsToAnimate.length; i < max; i++) {
let element = svgElementsToAnimate[i];
currentStrokeDashOffset = getCurrentAnimatePropertyValue(
element,
'stroke-dashoffset',
);
currentStrokeDashArray = getCurrentAnimatePropertyValue(
element,
'stroke-dasharray',
);
currentFillOpacity = getCurrentAnimatePropertyValue(
element,
'fill-opacity',
);
let currentAnimationTime = getCurrentAnimatePropertyValue(element, 'animation-duration');
elapsedTime = timer.pause();
let updatedAnimationTime = getUpdatedDurations(currentAnimationTime, elapsedTime)
element.style.animationPlayState = 'paused, paused';
element.style.webkitAnimationName = 'none';
element.style.strokeDashoffset = currentStrokeDashOffset;
element.style.strokeDasharray = currentStrokeDashArray;
element.style.fillOpacity = currentFillOpacity;
element.style.animationDuration = updatedAnimationTime;
changeAnimationStartKeyFrame([{ 'dash1': {'stroke-dashoffset': currentStrokeDashOffset }}, { 'fill': {'fill-opacity': currentFillOpacity }}])
}
divToBorderWithAnimatedSvg.style.borderImageSource = transformInDataUri(
svgAsBorderSelector,
);
});
});
.frame-1 {
border: 22px solid;
border-image-slice: 41;
border-image-width: 32px;
border-image-outset: 0;
border-image-repeat: stretch;
}
.blockquote-container blockquote, .blockquote-container blockquote p {
color: #a17c4a;
}
.blockquote-container blockquote {
padding: .5em;
}
<div class="blockquote-container">
<blockquote class="frame-1">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec placerat ex enim, nec tempus nisl commodo a. Nullam eu odio ut neque interdum mollis quis ac velit. Etiam pulvinar aliquam auctor.</p>
</blockquote>
</div>
<svg id='svg-as-border' class='svg-frame-1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 337 198'>
<g fill='none' fill-rule='evenodd'>
<style title="svg">
.path-1 {
stroke: #BEA757;
fill-opacity: 0;
stroke-width: 1;
stroke-dasharray: 1948px;
stroke-dashoffset: 1948px;
animation-name: dash1, fill;
animation-duration: 2s, 1s;
animation-fill-mode: forwards;
animation-delay: 0s, 0s;
animation-play-state: paused, paused;
}
#keyframes dash1 {
0% {
stroke-dashoffset: 1948px;
}
100% {
stroke-dashoffset: 0;
}
}
#keyframes fill {
80% {
fill-opacity: 0;
}
100% {
fill-opacity: 1;
}
}
</style>
<path class='path-1' fill='#BEA757'
d='M22.68,176.6 L315.68,176.6 L315.68,22.6 L22.68,22.6 L22.68,176.6 Z M331.596839,180.6 L332.68,180.6 L332.68,193.6 L319.68,193.6 L319.68,180.6 L331.596839,180.6 Z M18.68,191.363552 L18.68,193.6 L5.68,193.6 L5.68,180.6 L18.68,180.6 L18.68,191.363552 Z M9.65296139,18.6 L5.68,18.6 L5.68,5.6 L18.68,5.6 L18.68,18.6 L9.65296139,18.6 Z M319.68,12.191199 L319.68,5.6 L332.68,5.6 L332.68,18.6 L319.68,18.6 L319.68,12.191199 Z M331.333807,22.158844 L336.68,22.158844 L336.68,0.6 L315.049474,0.6 L315.049474,17.9061919 L22.3105259,17.9061919 L22.3105259,0.6 L0.68,0.6 L0.68,22.158844 L18.0579387,22.158844 L18.0579387,176.041156 L0.68,176.041156 L0.68,197.6 L22.3105259,197.6 L22.3105259,180.293808 L315.049474,180.293808 L315.049474,197.6 L336.68,197.6 L336.68,176.041156 L319.304352,176.041156 L319.304352,22.158844 L331.333807,22.158844 L331.333807,22.158844 Z' />
</g>
</svg>
put the SVG on page with the animations set to "paused"
in JavaScript, I've set a mouseenter event in which the animations of the SVG in page are set to "running", the Svg is transformed in data uri and assigned to the CSS border-image property as URL value
Similarly, in Js I've set a mouseleave event in which the animations of the Svg in page are set to "paused", the Svg is transformed in data uri and assigned to the CSS border-image property as URL value
The result is that when you "mouseenter" the blockquote, the animation starts but when you "mouseleave" the blockquote the animation visually reset to 0 and when you "mouseenter" again you can see that in the meantime the animation is over.
Why?
EDITED 2: the previous snippet had 2 problems:
you have to set to "none" the "animation-name" on mouseleave to "freeze" it
when you inject again the Svg as data uri in border-src before you have to change the animation-duration according to the remaining time to play (so I've inserted a timer function) and you have to change #keyframes injecting the new "start values" using CSSom: I've made this last thing but unfortunately the update CSSom is not "read" by the Svg as data uri and on mouseenter again the animation restarts...
Create your own Custom Element <bordered-svg> (supported in all modern Browsers) that dynamically creates the SVG with all unique values, no need for shadowDOM then.
If you add shadowDOM the CSS gets simpler, but controlling it from main DOM becomes more difficult.
<style>
div { width: 200px;display: grid;grid-template-columns: 1fr 1fr }
svg { width: 100%;vertical-align:top;cursor:pointer }
</style>
<div>
<bordered-svg color="red"></bordered-svg>
<bordered-svg color="gold"></bordered-svg>
<bordered-svg color="green"></bordered-svg>
<bordered-svg color="rebeccapurple"></bordered-svg>
</div>
<script>
customElements.define("bordered-svg", class extends HTMLElement {
connectedCallback() {
let uniqueID = "bordered" + Math.random().toString().substr(2, 8);
this.innerHTML = `
<svg id="${uniqueID}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 6 6">
<style>
#${uniqueID} path {
stroke:${this.getAttribute("color")||"grey"};
stroke-width:3; stroke-dasharray: 12;
animation-name: animation${uniqueID};
animation-duration: 5s;
animation-play-state: paused;
}
#keyframes animation${uniqueID} {
0% { stroke-dashoffset:0 }
100%{ stroke-dashoffset:1000 }
}
</style>
<path fill='none' d='M0 0h6v6h-6z'></path></svg>`;
let style = this.querySelector(`#${uniqueID} path`).style;
this.onmouseenter = () => style.animationPlayState = "running";
this.onmouseleave = () => style.animationPlayState = "paused";
}
});
</script>
Last example: animated SVG border with play/pause states
<style>
animated-border {
--animated-border-stroke: black;
--animated-border-fill: darkgoldenrod;
--animated-border-playstate: running;
--animated-border-height: 100px;
}
animated-border [slot="content"] {
text-align: center;
height: 100%;
padding-top: 2em;
}
</style>
<animated-border>
<div slot="content">
<h2>
Once Upon A Time...
</h2>
<b>there was a Web Component</b>
</div>
</animated-border>
<script>
customElements.define("animated-border", class extends HTMLElement {
// Animate a border picture frame. paths 1-3 are animated, path 4 is the always visible path'
constructor() {
let animate = (nr, duration, delay, dash = 2000) => `
#path${nr}{
stroke-dasharray:${dash};
stroke-dashoffset:${dash};
animation-name:dash${nr};
animation-duration:${duration}s;
animation-delay:${delay}s
}
#keyframes dash${nr}{
0%{stroke-dashoffset:${dash}}
80%{fill-opacity:0}
100%{fill-opacity:1;stroke-dashoffset:0}}`;
//console.warn(animate(1, "2s,1s", "0s,0s"));
let style = `<style>:host{
display:inline-block;
--height:var(--animated-border-height,150px);
height: var(--height);
width:calc(2 * var(--height));
}
svg{
background:var(--animated-border-background,transparent);
width:100%;
height:100%;
}
[id*="path"]{
stroke:var(--animated-border-stroke);
fill:var(--animated-border-fill);
fill-opacity:0;stroke-width:2;
animation-fill-mode:forwards;
animation-play-state:var(--animated-border-playstate,paused)}
${animate(1,1,0)}
${animate(2,2,0)}
${animate(3,2,1)}
</style>`;
super().attachShadow({
mode: "open"
}).innerHTML = style + `<div></div>`;
this.border = this.shadowRoot.querySelector('div');
}
render() {
let random = Math.floor(1000 + Math.random() * 9000);
let path = (nr, d) => `<path id='path${nr}' random='${random}' d='${d}'/>`;
let svg =
path(1, 'm23 177l293 0l0-154l-293 0l0 154zm309 4l1 0l0 13l-13 0l0-13l12 0zm-313 10l0 3l-13 0l0-13l13 0l0 10zm-9-172l-4 0l0-13l13 0l0 13l-9 0zm310-7l0-6l13 0l0 13l-13 0l0-7zm11 10l6 0l0-21l-22 0l0 17l-293 0l0-17l-21 0l0 21l17 0l0 154l-17 0l0 22l21 0l0-18l293 0l0 18l22 0l0-22l-18 0l0-154l12 0l0 0z') +
path(2, 'm31 185l275 0c3-9 9-15 18-18l0-136c-9-3-15-9-18-17l-275 0c-3 8-9 14-17 17l0 136c8 3 14 9 17 18zm278 4l-280 0l-1-2c-2-8-9-14-17-17l-1 0l0-142l1 0c8-3 15-9 17-17l1-1l280 0l0 1c3 8 9 14 17 17l2 0l0 142l-2 0c-8 3-14 9-17 17l0 2l0 0z') +
path(3, 'm49 194l241 0c0-6 1-11 3-16c2-5 6-10 10-14c4-4 9-8 14-10c5-2 10-3 16-3l0-102c-6-1-11-2-16-4c-5-2-10-5-14-10c-4-4-8-9-10-14c-2-5-3-10-3-15l-241 0c-1 5-2 10-4 15c-2 5-5 10-9 14c-5 5-9 8-15 10c-5 2-10 3-15 4l0 102c5 0 10 1 15 3c6 2 10 6 15 10c4 4 7 9 9 14c2 5 3 10 4 16zm245 4l-250 0l0-3c0-22-19-40-41-40l-2 0l0-111l2 0c22 0 41-19 41-41l0-2l250 0l0 2c0 22 18 41 41 41l2 0l0 111l-2 0c-23 0-41 18-41 40l0 3l0 0z') +
path(4, 'm294 185l0 4l-251 0l0-4l251 0zm-280-142l0 111l-4 0l0-111l4 0zm314 0l0 111l-4 0l0-111l4 0zm-34-33l0 4l-251 0l0-4l251 0zm-263 175l275 0c3-9 9-15 18-18l0-136c-9-3-15-9-18-17l-275 0c-3 8-9 14-17 17l0 136c8 3 14 9 17 18zm-2 4l-1-2c-2-8-9-14-17-17l-1 0l0-142l1 0c8-3 15-9 17-17l1-1l280 0l0 1c3 8 9 14 17 17l2 0l0 142l-2 0c-8 3-14 9-17 17l0 2l-280 0z');
svg = svg.replace(/\s+/g, ' ');
svg = svg.replace(/#/g, "%23");
svg = svg.replace(/"/g, "'");
svg = `<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 340 200' fill-rule='evenodd'>${svg}<foreignObject x="0" y="0" width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml" style="width:100%;height:100%;position:absolute"><slot name="content"></slot></div>
</foreignObject></svg>`;
this.shadowRoot.querySelector("div").innerHTML = svg;
}
connectedCallback() {
this.onmouseenter = () => this.play();
this.onmouseleave = () => this.pause();
this.border.addEventListener("animationend", (evt) => {
this.animatedpathcount--;
if (!this.animatedpathcount) this.end();
})
this.playstate = "paused";
this.restart();
}
log(...args) {
console.log(`%cBorderMeister`, "background:teal;color:white", ...args);
}
set playstate(state = "running") {
this.style.setProperty("--animated-border-playstate", state);
}
get playstate() {
return this.style.getPropertyValue("--animated-border-playstate");
}
restart() {
this.log("restart");
this.animatedpathcount = 3;
this.render();
}
play() {
this.log("play")
if (!this.animatedpathcount) this.restart();
this.playstate = "running";
}
pause() {
this.log("pause")
this.playstate = "paused";
}
end() {
this.log("end")
this.playstate = "paused";
}
});
</script>
I have a slider(source code here) that currently has it's height set to 100%. However, I want the slider to have a height of 550px so it does not look too big, but am not managing to get that right for some reason.
Below is the full code and running snippet:
(function(factory){
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof exports !== 'undefined') {
module.exports = factory(require('jquery'));
} else {
factory(jQuery);
}
})(function($){
var Zippy = (function(element, settings){
var instanceUid = 0;
function _Zippy(element, settings){
this.defaults = {
slideDuration: '3000',
speed: 500,
arrowRight: '.arrow-right',
arrowLeft: '.arrow-left'
};
this.settings = $.extend({},this,this.defaults,settings);
this.initials = {
currSlide : 0,
$currSlide: null,
totalSlides : false,
csstransitions: false
};
$.extend(this,this.initials);
this.$el = $(element);
this.changeSlide = $.proxy(this.changeSlide,this);
this.init();
this.instanceUid = instanceUid++;
}
return _Zippy;
})();
Zippy.prototype.init = function(){
this.csstransitionsTest();
this.$el.addClass('zippy-carousel');
this.build();
this.events();
this.activate();
this.initTimer();
};
Zippy.prototype.csstransitionsTest = function(){
var elem = document.createElement('modernizr');
var props = ["transition","WebkitTransition","MozTransition","OTransition","msTransition"];
for ( var i in props ) {
var prop = props[i];
var result = elem.style[prop] !== undefined ? prop : false;
if (result){
this.csstransitions = result;
break;
}
}
};
Zippy.prototype.addCSSDuration = function(){
var _ = this;
this.$el.find('.slide').each(function(){
this.style[_.csstransitions+'Duration'] = _.settings.speed+'ms';
});
}
Zippy.prototype.removeCSSDuration = function(){
var _ = this;
this.$el.find('.slide').each(function(){
this.style[_.csstransitions+'Duration'] = '';
});
}
Zippy.prototype.build = function(){
var $indicators = this.$el.append('<ul class="indicators" >').find('.indicators');
this.totalSlides = this.$el.find('.slide').length;
for(var i = 0; i < this.totalSlides; i++) $indicators.append('<li data-index='+i+'>');
};
Zippy.prototype.activate = function(){
this.$currSlide = this.$el.find('.slide').eq(0);
this.$el.find('.indicators li').eq(0).addClass('active');
};
Zippy.prototype.events = function(){
$('body')
.on('click',this.settings.arrowRight,{direction:'right'},this.changeSlide)
.on('click',this.settings.arrowLeft,{direction:'left'},this.changeSlide)
.on('click','.indicators li',this.changeSlide);
};
Zippy.prototype.clearTimer = function(){
if (this.timer) clearInterval(this.timer);
};
Zippy.prototype.initTimer = function(){
this.timer = setInterval(this.changeSlide, this.settings.slideDuration);
};
Zippy.prototype.startTimer = function(){
this.initTimer();
this.throttle = false;
};
Zippy.prototype.changeSlide = function(e){e
if (this.throttle) return;
this.throttle = true;
this.clearTimer();
var direction = this._direction(e);
var animate = this._next(e,direction);
if (!animate) return;
var $nextSlide = this.$el.find('.slide').eq(this.currSlide).addClass(direction + ' active');
if (!this.csstransitions){
this._jsAnimation($nextSlide,direction);
} else {
this._cssAnimation($nextSlide,direction);
}
};
Zippy.prototype._direction = function(e){
var direction;
// Default to forward movement
if (typeof e !== 'undefined'){
direction = (typeof e.data === 'undefined' ? 'right' : e.data.direction);
} else {
direction = 'right';
}
return direction;
};
Zippy.prototype._next = function(e,direction){
var index = (typeof e !== 'undefined' ? $(e.currentTarget).data('index') : undefined);
switch(true){
case( typeof index !== 'undefined'):
if (this.currSlide == index){
this.startTimer();
return false;
}
this.currSlide = index;
break;
case(direction == 'right' && this.currSlide < (this.totalSlides - 1)):
this.currSlide++;
break;
case(direction == 'right'):
this.currSlide = 0;
break;
case(direction == 'left' && this.currSlide === 0):
this.currSlide = (this.totalSlides - 1);
break;
case(direction == 'left'):
this.currSlide--;
break;
}
return true;
};
Zippy.prototype._cssAnimation = function($nextSlide,direction){
setTimeout(function(){
this.$el.addClass('transition');
this.addCSSDuration();
this.$currSlide.addClass('shift-'+direction);
}.bind(this),100);
setTimeout(function(){
this.$el.removeClass('transition');
this.removeCSSDuration();
this.$currSlide.removeClass('active shift-left shift-right');
this.$currSlide = $nextSlide.removeClass(direction);
this._updateIndicators();
this.startTimer();
}.bind(this),100 + this.settings.speed);
};
Zippy.prototype._jsAnimation = function($nextSlide,direction){
var _ = this;
if(direction == 'right') _.$currSlide.addClass('js-reset-left');
var animation = {};
animation[direction] = '0%';
var animationPrev = {};
animationPrev[direction] = '100%';
this.$currSlide.animate(animationPrev,this.settings.speed);
$nextSlide.animate(animation,this.settings.speed,'swing',function(){
_.$currSlide.removeClass('active js-reset-left').attr('style','');
_.$currSlide = $nextSlide.removeClass(direction).attr('style','');
_._updateIndicators();
_.startTimer();
});
};
Zippy.prototype._updateIndicators = function(){
this.$el.find('.indicators li').removeClass('active').eq(this.currSlide).addClass('active');
};
$.fn.Zippy = function(options){
return this.each(function(index,el){
el.Zippy = new Zippy(el,options);
});
};
});
var args = {
arrowRight : '.arrow-right',
arrowLeft : '.arrow-left',
speed : 1000,
slideDuration : 4000
};
$('.carousel').Zippy(args);
(function(factory){
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof exports !== 'undefined') {
module.exports = factory(require('jquery'));
} else {
factory(jQuery);
}
})(function($){
var Zippy = (function(element, settings){
var instanceUid = 0;
function _Zippy(element, settings){
this.defaults = {
slideDuration: '3000',
speed: 500,
arrowRight: '.arrow-right',
arrowLeft: '.arrow-left'
};
this.settings = $.extend({},this,this.defaults,settings);
this.initials = {
currSlide : 0,
$currSlide: null,
totalSlides : false,
csstransitions: false
};
$.extend(this,this.initials);
this.$el = $(element);
this.changeSlide = $.proxy(this.changeSlide,this);
this.init();
this.instanceUid = instanceUid++;
}
return _Zippy;
})();
Zippy.prototype.init = function(){
this.csstransitionsTest();
this.$el.addClass('zippy-carousel');
this.build();
this.events();
this.activate();
this.initTimer();
};
Zippy.prototype.csstransitionsTest = function(){
var elem = document.createElement('modernizr');
var props = ["transition","WebkitTransition","MozTransition","OTransition","msTransition"];
for ( var i in props ) {
var prop = props[i];
var result = elem.style[prop] !== undefined ? prop : false;
if (result){
this.csstransitions = result;
break;
}
}
};
Zippy.prototype.addCSSDuration = function(){
var _ = this;
this.$el.find('.slide').each(function(){
this.style[_.csstransitions+'Duration'] = _.settings.speed+'ms';
});
}
Zippy.prototype.removeCSSDuration = function(){
var _ = this;
this.$el.find('.slide').each(function(){
this.style[_.csstransitions+'Duration'] = '';
});
}
Zippy.prototype.build = function(){
var $indicators = this.$el.append('<ul class="indicators" >').find('.indicators');
this.totalSlides = this.$el.find('.slide').length;
for(var i = 0; i < this.totalSlides; i++) $indicators.append('<li data-index='+i+'>');
};
Zippy.prototype.activate = function(){
this.$currSlide = this.$el.find('.slide').eq(0);
this.$el.find('.indicators li').eq(0).addClass('active');
};
Zippy.prototype.events = function(){
$('body')
.on('click',this.settings.arrowRight,{direction:'right'},this.changeSlide)
.on('click',this.settings.arrowLeft,{direction:'left'},this.changeSlide)
.on('click','.indicators li',this.changeSlide);
};
Zippy.prototype.clearTimer = function(){
if (this.timer) clearInterval(this.timer);
};
Zippy.prototype.initTimer = function(){
this.timer = setInterval(this.changeSlide, this.settings.slideDuration);
};
Zippy.prototype.startTimer = function(){
this.initTimer();
this.throttle = false;
};
Zippy.prototype.changeSlide = function(e){e
if (this.throttle) return;
this.throttle = true;
this.clearTimer();
var direction = this._direction(e);
var animate = this._next(e,direction);
if (!animate) return;
var $nextSlide = this.$el.find('.slide').eq(this.currSlide).addClass(direction + ' active');
if (!this.csstransitions){
this._jsAnimation($nextSlide,direction);
} else {
this._cssAnimation($nextSlide,direction);
}
};
Zippy.prototype._direction = function(e){
var direction;
// Default to forward movement
if (typeof e !== 'undefined'){
direction = (typeof e.data === 'undefined' ? 'right' : e.data.direction);
} else {
direction = 'right';
}
return direction;
};
Zippy.prototype._next = function(e,direction){
var index = (typeof e !== 'undefined' ? $(e.currentTarget).data('index') : undefined);
switch(true){
case( typeof index !== 'undefined'):
if (this.currSlide == index){
this.startTimer();
return false;
}
this.currSlide = index;
break;
case(direction == 'right' && this.currSlide < (this.totalSlides - 1)):
this.currSlide++;
break;
case(direction == 'right'):
this.currSlide = 0;
break;
case(direction == 'left' && this.currSlide === 0):
this.currSlide = (this.totalSlides - 1);
break;
case(direction == 'left'):
this.currSlide--;
break;
}
return true;
};
Zippy.prototype._cssAnimation = function($nextSlide,direction){
setTimeout(function(){
this.$el.addClass('transition');
this.addCSSDuration();
this.$currSlide.addClass('shift-'+direction);
}.bind(this),100);
setTimeout(function(){
this.$el.removeClass('transition');
this.removeCSSDuration();
this.$currSlide.removeClass('active shift-left shift-right');
this.$currSlide = $nextSlide.removeClass(direction);
this._updateIndicators();
this.startTimer();
}.bind(this),100 + this.settings.speed);
};
Zippy.prototype._jsAnimation = function($nextSlide,direction){
var _ = this;
if(direction == 'right') _.$currSlide.addClass('js-reset-left');
var animation = {};
animation[direction] = '0%';
var animationPrev = {};
animationPrev[direction] = '100%';
this.$currSlide.animate(animationPrev,this.settings.speed);
$nextSlide.animate(animation,this.settings.speed,'swing',function(){
_.$currSlide.removeClass('active js-reset-left').attr('style','');
_.$currSlide = $nextSlide.removeClass(direction).attr('style','');
_._updateIndicators();
_.startTimer();
});
};
Zippy.prototype._updateIndicators = function(){
this.$el.find('.indicators li').removeClass('active').eq(this.currSlide).addClass('active');
};
$.fn.Zippy = function(options){
return this.each(function(index,el){
el.Zippy = new Zippy(el,options);
});
};
});
var args = {
arrowRight : '.arrow-right',
arrowLeft : '.arrow-left',
speed : 1000,
slideDuration : 4000
};
$('.carousel').Zippy(args);
<div class="wrapper">
<div class="carousel">
<div class="inner">
<div class="slide active">
<div class="slide-box">
<h1>1</h1>
<h2>Heading 2</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.</p>
</div>
</div>
<div class="slide">
<div class="slide-box">
<h1>2</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.</p>
</div>
</div>
<div class="slide">
<div class="slide-box">
<h1>3</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.</p>
</div>
</div>
</div>
<div class="arrow arrow-left"></div>
<div class="arrow arrow-right"></div>
</div>
</div>
I tried giving a height of 500px to the wrapper class but it does not seem to be the best way.
How can I adjust the height of the slider and also keep the content in the middle of the box when I resize the page?
Here mycodepen if needed
Thank you in advance
The padding in the slide style give problems with height:
.slide {
text-align: center;
padding-top: 25%;
background-size: cover;
}
This is my fix to your style to get the right height, I also centered horizontally and vertically the slide-box and the text:
/********For better see the text********/
p{
color:white;
}
h2{
color:white;
}
/**************************************/
.wrapper{
width:100%;
position:relative;
height: 50px;
}
.slide-box {
max-width: 1300px;
margin: 0 auto;
padding: 54px;
position: relative;
top: 50%;
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
/**
* Padding is set relative to the width
* of the element, so here padding-top:60% is
* a percentage of the width. This allows us
* to set the height as a ratio of the width
*
*/
.carousel{
width: 100%;
height: 500px;
position: relative;
/* padding-top: 50%; */
overflow: hidden;
}
.inner{
width: 100%;
height: 100%;
position: absolute;
top:0;
left: 0;
}
/**
* ==========================
* Animation styles
*
* Notes:
* 1. We use z-index to position active slides in-front
* of non-active slides
* 2. We set right:0 and left:0 on .slide to provide us with
* a default positioning on both sides of the slide. This allows
* us to trigger JS and CSS3 animations easily
*
*/
.slide{
width: 100%;
height: 500px;
position: absolute;
top:0;
right:0;
left:0;
z-index: 1;
opacity: 0;
}
.slide.active,
.slide.left,
.slide.right{
z-index: 2;
opacity: 1;
}
/**
* ==========================
* JS animation styles
*
* We use jQuery.animate to control the sliding animations
* when CSS3 animations are not available. In order for
* the next slide to slide in from the right, we need
* to change the left:0 property of the slide to left:auto
*
*/
.js-reset-left{left:auto}
/**
* ==========================
* CSS animation styles
*
* .slide.left and .slide.right set-up
* the to-be-animated slide so that it can slide
* into view. For example, a slide that is about
* to slide in from the right will:
* 1. Be positioned to the right of the viewport (right:-100%)
* 2. Slide in when the style is superseded with a more specific style (right:0%)
*
*/
.slide.left{
left:-100%;
right:0;
}
.slide.right{
right:-100%;
left: auto;
}
.transition .slide.left{left:0%}
.transition .slide.right{right:0%}
/**
* The following classes slide the previously active
* slide out of view before positioning behind the
* currently active slide
*
*/
.transition .slide.shift-right{right: 100%;left:auto}
.transition .slide.shift-left{left: 100%;right:auto}
/**
* This sets the CSS properties that will animate. We set the
* transition-duration property dynamically via JS.
* We use the browser's default transition-timing-function
* for simplicity's sake
*
* It is important to note that we are using CodePen's inbuilt
* CSS3 property prefixer. For your own projects, you will need
* to prefix the transition and transform properties here to ensure
* reliable support across browsers
*
*/
.transition .slide{
transition-property: right, left, margin;
}
/**
* ==========================
* Indicators
*
*/
.indicators{
width:100%;
position: absolute;
bottom:0;
z-index: 4;
padding:0;
text-align: center;
}
.indicators li{
width: 13px;
height: 13px;
display: inline-block;
margin: 5px;
background: #fff;
list-style-type: none;
border-radius: 50%;
cursor:pointer;
transition:background 0.3s ease-out;
}
.indicators li.active{background:#93278f}
.indicators li:hover{background-color:#2b2b2b}
/**
* ==========================
* Arrows
*
*/
.arrow{
width: 20px;
height: 20px;
position:absolute;
top:50%;
z-index:5;
border-top:3px solid #fff;
border-right:3px solid #fff;
cursor:pointer;
transition:border-color 0.3s ease-out;
}
.arrow:hover{border-color:#93278f}
.arrow-left{
left:20px;
transform:rotate(225deg);
}
.arrow-right{
right:20px;
transform:rotate(45deg);
}
/**
* ==========================
* For demo purposes only
*
* Please note that the styles below are used
* for the purposes of this demo only. There is no need
* to use these in any of your own projects
*
*/
.slide{
text-align:left;
background-size:cover;
display: table-cell;
vertical-align: middle;
}
h1{
width:100px;
height:100px;
background-color:rgba(146, 45, 141,0.7);
margin:auto;
line-height:100px;
color:#fff;
font-size:2.4em;
border-radius:50%;
text-align: center;
}
.slide:nth-child(1){
background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/163697/slide-1.jpg);
}
.slide:nth-child(2){
background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/163697/slide-2.jpg);
}
.slide:nth-child(3){
background-image:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/163697/slide-3.jpg);
}
Here is a link to the website so that you can visualize the error im expressing in my title:
https://glassesled.com/aubrey
If you hover over the picture the zoom box doesn't follow the cursor and when you go the lower portions of the image the zoom box reaches a wall. Here are the relevant files (the ones I think are relevant)
The CloudZoom.min.js file
//////////////////////////////////////////////////////////////////////////////////
// Cloud Zoom V1.0.2
// (c) 2010 by R Cecco. <http://www.professorcloud.com>
// MIT License
//
// Please retain this copyright header in all versions of the software
//////////////////////////////////////////////////////////////////////////////////
! function($) {
function format(t) {
for (var o = 1; o < arguments.length; o++) t = t.replace("%" + (o - 1), arguments[o]);
return t
}
function CloudZoom(t, o) {
var e, i, s, a, n, r, l, d, u = $("img", t),
p = null,
c = null,
h = null,
m = null,
f = null,
g = null,
v = 0,
x = 0,
b = 0,
y = 0,
z = 0,
w = 0,
O = this;
setTimeout(function() {
if (null === c) {
var o = t.width();
t.parent().append(format('<div style="width:%0px;position:absolute;top:75%;left:%1px;text-align:center" class="cloud-zoom-loading" >Loading...</div>', o / 3, o / 2 - o / 6)).find(":last").css("opacity", .5)
}
}, 200);
var k = function() {
null !== g && (g.remove(), g = null)
};
this.removeBits = function() {
h && (h.remove(), h = null), m && (m.remove(), m = null), f && (f.remove(), f = null), k(), $(".cloud-zoom-loading", t.parent()).remove()
}, this.destroy = function() {
t.data("zoom", null), c && (c.unbind(), c.remove(), c = null), p && (p.remove(), p = null), this.removeBits()
}, this.fadedOut = function() {
p && (p.remove(), p = null), this.removeBits()
}, this.controlLoop = function() {
if (h) {
var t = r - u.offset().left - .5 * a >> 0,
e = l - u.offset().top - .5 * n >> 0;
0 > t ? t = 0 : t > u.outerWidth() - a && (t = u.outerWidth() - a), 0 > e ? e = 0 : e > u.outerHeight() - n && (e = u.outerHeight() - n), h.css({
left: t,
top: e
}), h.css("background-position", -t + "px " + -e + "px"), x = t / u.outerWidth() * s.width >> 0, b = e / u.outerHeight() * s.height >> 0, z += (x - z) / o.smoothMove, y += (b - y) / o.smoothMove, p.css("background-position", -(z >> 0) + "px " + (-(y >> 0) + "px"))
}
v = setTimeout(function() {
O.controlLoop()
}, 30)
}, this.init2 = function(t, o) {
w++, 1 === o && (s = t), 2 === w && this.init()
}, this.init = function() {
$(".cloud-zoom-loading", t.parent()).remove();
var e = $(".mousetrap");
e && e.remove(), c = $.browser.msie ? t.parent().append(format("<div class='mousetrap' style='background-image:url(\"/Plugins/SevenSpikes.Nop.Plugins.CloudZoom/Scripts/cloud-zoom.1.0.2/DummyPageForIE.htm\");z-index:999;position:absolute;width:%0px;height:%1px;left:%2px;top:%3px;'></div>", u.outerWidth(), u.outerHeight(), 0, 0)).find(":last") : t.parent().append(format("<div class='mousetrap' style='z-index:999;position:absolute;width:%0px;height:%1px;left:%2px;top:%3px;'></div>", u.outerWidth(), u.outerHeight(), 0, 0)).find(":last"), c.bind("mousemove", this, function(t) {
r = t.pageX, l = t.pageY
}), c.bind("mouseleave", this, function(t) {
return clearTimeout(v), h && h.fadeOut(299), m && m.fadeOut(299), f && f.fadeOut(299), p.fadeOut(300, function() {
O.fadedOut()
}), !1
}), c.bind("mouseenter", this, function(e) {
r = e.pageX, l = e.pageY, d = e.data, p && (p.stop(!0, !1), p.remove());
var i = o.adjustX,
v = o.adjustY,
x = u.outerWidth(),
b = u.outerHeight(),
y = o.zoomWidth,
z = o.zoomHeight;
"auto" == o.zoomWidth && (y = x), "auto" == o.zoomHeight && (z = b);
var w = t.parent();
switch (o.position) {
case "top":
v -= z;
break;
case "right":
i += x;
break;
case "bottom":
v += b;
break;
case "left":
i -= y;
break;
case "inside":
y = x, z = b;
break;
default:
w = $("#" + o.position), w.length ? (y = o.zoomWidth, z = o.zoomHeight) : (w = t, i += x, v += b)
}
p = w.append(format('<div id="cloud-zoom-big" class="cloud-zoom-big" style="display:none;position:absolute;left:%0px;top:%1px;width:%2px;height:%3px;background-image:url(\'%4\');z-index:99;"></div>', i, v, y, z, s.src)).find(":last"), u.attr("title") && o.showTitle && p.append(format('<div class="cloud-zoom-title">%0</div>', u.attr("title"))).find(":last").css("opacity", o.titleOpacity), $.browser.msie && $.browser.version < 7 && (g = $('<iframe frameborder="0" src="#"></iframe>').css({
position: "absolute",
left: i,
top: v,
zIndex: 99,
width: y,
height: z
}).insertBefore(p)), p.fadeIn(500), h && (h.remove(), h = null), a = u.outerWidth() / s.width * p.width(), n = u.outerHeight() / s.height * p.height(), h = t.append(format("<div class = 'cloud-zoom-lens' style='display:none;z-index:98;position:absolute;width:%0px;height:%1px;'></div>", a, n)).find(":last"), c.css("cursor", h.css("cursor"));
var O = !1;
o.tint && (h.css("background", 'url("' + u.attr("src") + '")'), m = t.append(format('<div class="cloud-zoom-tint" style="display:none;position:absolute; left:0px; top:0px; width:%0px; height:%1px; background-color:%2;" />', u.outerWidth(), u.outerHeight(), o.tint)).find(":last"), m.css("opacity", o.tintOpacity), O = !0, m.fadeIn(500)), o.softFocus && (h.css("background", 'url("' + u.attr("src") + '")'), f = t.append(format('<div class="cloud-zoom-softfocus" style="position:absolute;display:none;top:2px; left:2px; width:%0px; height:%1px;" />', u.outerWidth() - 2, u.outerHeight() - 2, o.tint)).find(":last"), f.css("background", 'url("' + u.attr("src") + '")'), f.css("opacity", .5), O = !0, f.fadeIn(500)), O || h.css("opacity", o.lensOpacity), "inside" !== o.position && h.fadeIn(500), d.controlLoop()
})
}, e = new Image, $(e).load(function() {
O.init2(this, 0)
}), e.src = u.attr("src"), i = new Image, $(i).load(function() {
O.init2(this, 1)
}), i.src = t.attr("href")
}
$(document).ready(function() {
$(".cloud-zoom, .cloud-zoom-gallery").CloudZoom()
}), $.fn.CloudZoom = function(options) {
try {
document.execCommand("BackgroundImageCache", !1, !0)
} catch (e) {}
return this.each(function() {
var relOpts, opts;
eval("var a = {" + $(this).attr("rel") + "}"), relOpts = a, $(this).is(".cloud-zoom") ? ($(this).css({
position: "relative",
display: "block"
}), $("img", $(this)).css({
display: "block"
}), "wrap" != $(this).parent().attr("id") && $(this).wrap('<div id="wrap" style="top:0px;position:relative;"></div>'), opts = $.extend({}, $.fn.CloudZoom.defaults, options), opts = $.extend({}, opts, relOpts), $(this).data("zoom", new CloudZoom($(this), opts))) : $(this).is(".cloud-zoom-gallery") && (opts = $.extend({}, relOpts, options), $(this).data("relOpts", opts), $(this).bind("click", $(this), function(t) {
var o = t.data.data("relOpts");
return $("#" + o.useZoom).data("zoom").destroy(), $("#" + o.useZoom).attr("href", t.data.attr("href")), $("#" + o.useZoom).attr("rel", t.data.attr("rel")), $("#" + o.useZoom + " img").attr("title", t.data.attr("title")), $("#" + o.useZoom + " img").attr("src", t.data.data("relOpts").smallImage), $("#" + t.data.data("relOpts").useZoom).CloudZoom(), !1
}))
}), this
}, $.fn.CloudZoom.defaults = {
zoomWidth: "auto",
zoomHeight: "auto",
position: "right",
tint: !1,
tintOpacity: .5,
lensOpacity: .5,
softFocus: !1,
smoothMove: 3,
showTitle: !0,
titleOpacity: .5,
adjustX: 0,
adjustY: 0
}
}(jQuery);
CSS file used in cshtml
/*
* Copyright 2014 Seven Spikes Ltd. All rights reserved. (http://www.nop-templates.com)
* http://www.nop-templates.com/t/licensinginfo
*/
#media all and (max-width: 1000px) {
#sevenspikes-cloud-zoom:before {
display: none;
}
#sevenspikes-cloud-zoom img {
position: static;
}
}
#media all and (min-width: 1001px) {
/* theme overwritting styles */
.gallery {
font-size: 0;
}
.gallery .picture-wrapper {
/*** !!! set line-height to the appropriate height !!! ***/
line-height: 320px;
}
.gallery .picture-wrapper .picture:before {
display: none;
}
/* main picture styles */
#sevenspikes-cloud-zoom {
margin: 0;
overflow: visible;
text-align: center;
font-size: 0;
}
#sevenspikes-cloud-zoom:before {
display: none;
}
#wrap {
display: block;
max-width: 100%;
vertical-align: middle;
line-height: 0;
}
#wrap a {
position: relative;
max-width: 100%;
vertical-align: middle;
line-height: 0;
overflow: hidden;
}
#wrap a:before {
content: "";
display: block;
padding-top: 125%;
}
#wrap img {
}
/* This is the overlay element. */
#wrap > .mousetrap {
right: 0;
bottom: 0;
margin: auto;
}
.cloud-zoom-lens {
margin: 0;
border: none;
background-color: #fff;
cursor: crosshair;
}
/* This is the zoom window. */
#cloudZoomWindowElement {
left: 0;
top: 0;
z-index: 1;
}
#cloud-zoom-big {
border: none;
overflow: hidden;
bottom: 0;
margin: auto;
}
.overview #cloud-zoom-big {
position: static !important; /* fix for the zoom window so that its wrapper takes the dimensions */
}
/* This is for the title text. */
.cloud-zoom-title {
background-color: #000;
padding: 5px;
text-align: center;
font-size: 11px;
line-height: normal;
font-weight: bold;
color: #fff;
}
/* This is the loading message. */
.cloud-zoom-loading {
width: 100% !important;
height: 100% !important;
top: 0 !important;
left: 0 !important;
right: 0 !important;
bottom: 0 !important;
font-size: 0;
background: rgba(255,255,255,.5);
opacity: 1 !important;
}
#keyframes spinner {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.cloud-zoom-loading:after,
.cloud-zoom-loading:before {
content: '';
position: absolute;
border: 2px solid #454545;
width: 30px;
height: 30px;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
outline: 1px solid transparent; /*firefox fix*/
}
.cloud-zoom-loading:after {
animation: spinner 2.5s linear infinite;
}
.cloud-zoom-loading:before {
width: 44px;
height: 44px;
animation: spinner 2.5s linear infinite;
animation-direction: reverse;
}
/* with product ribbons enabled */
.gallery .ribbon-wrapper {
/*never display as inline or inline-block*/
vertical-align: middle;
line-height: 0;
}
.gallery .ribbon-wrapper:hover .ribbon-position {
opacity: 0;
}
}
CSHTML file
#** Copyright 2016 Seven Spikes Ltd. All rights reserved. (http://www.nop-templates.com)
* http://www.nop-templates.com/t/licensinginfo
*#
#using Nop.Core
#using Nop.Core.Infrastructure
#using SevenSpikes.Nop.Plugins.CloudZoom.Models
#model CloudZoomModel
#if (!string.IsNullOrEmpty(Model.DefaultPicture.FullSizeImageUrl))
{
Html.AddCssFileParts("~/Plugins/SevenSpikes.Nop.Plugins.CloudZoom/Themes/" + Model.Theme + "/Content/cloud-zoom.1.0.2/CloudZoom.css");
var supportRtl = EngineContext.Current.Resolve<IWorkContext>().WorkingLanguage.Rtl;
if (supportRtl)
{
Html.AddCssFileParts("~/Plugins/SevenSpikes.Nop.Plugins.CloudZoom/Styles/CloudZoom.common.rtl.css");
}
Html.AddScriptParts("~/Plugins/SevenSpikes.Core/Scripts/SevenSpikesExtensions.min.js");
Html.AddScriptParts("~/Plugins/SevenSpikes.Nop.Plugins.CloudZoom/Scripts/cloud-zoom.1.0.2/cloud-zoom.1.0.2.min.js");
if (Model.IsIntegratedByWidget)
{
Html.AddScriptParts("~/Plugins/SevenSpikes.Nop.Plugins.CloudZoom/Scripts/CloudZoom.min.js");
}
if (Model.EnableClickToZoom)
{
Html.AddCssFileParts("~/Content/magnific-popup/magnific-popup.css");
Html.AddScriptParts("~/Scripts/jquery.magnific-popup.min.js");
<script type="text/javascript">
$(document).ready(function () {
$(".picture").on("click", ".mousetrap", function () {
var mainPictureHref = $('.picture a.cloud-zoom').attr('href');
var cloudZoomThumbs = $('.picture-thumbs a.cloud-zoom-gallery');
var imgSources = new Array();
var imgItem = function(source) {
this.src = source;
};
cloudZoomThumbs.each(function(){
imgSources.push(new imgItem($(this).attr('href')));
});
if(imgSources.length === 0){
imgSources.push(new imgItem(mainPictureHref));
}
$.magnificPopup.open({
items: imgSources,
type: 'image',
removalDelay: 300,
gallery: {
enabled: true
}
}, cloudZoomThumbs.filter('.active').index());
});
});
</script>
}
<script type="text/javascript">
#{
string pictureAdjustmentTableName = string.Format("productAttributeValueAdjustmentTable_{0}", Model.ProductId);
string pictureAdjustmentFuncName = string.Format("adjustProductAttributeValuePicture_CloudZoom_{0}", Model.ProductId);
string pictureFullSizePrefix = "fullsize";
}
function #(pictureAdjustmentFuncName)(controlId) {
var ctrl = $('#' + controlId);
var pictureFullSizeUrl = '';
if((ctrl.is(':radio') && ctrl.is(':checked')) || (ctrl.is(':checkbox') && ctrl.is(':checked'))) {
pictureFullSizeUrl = #(pictureAdjustmentTableName)[controlId + '_#(pictureFullSizePrefix)'];
} else if(ctrl.is('select')) {
var idx = $('#' + controlId + " option").index($('#' + controlId + " option:selected"));
if(idx !== -1) {
pictureFullSizeUrl = #(pictureAdjustmentTableName)[controlId + '_#(pictureFullSizePrefix)'][idx];
}
}
if (typeof pictureFullSizeUrl == 'string' && pictureFullSizeUrl !== '') {
var zoomGallerySelector = ".cloud-zoom-gallery[href='" + pictureFullSizeUrl + "']";
$(zoomGallerySelector).click();
$.event.trigger({
type: 'nopMainProductImageChanged',
target: ctrl,
pictureDefaultSizeUrl: pictureFullSizeUrl,
pictureFullSizeUrl: pictureFullSizeUrl
});
}
}
$(document).ready(function () {
$("[id^='product_attribute_']").on('change', function() {
#(pictureAdjustmentFuncName)($(this).attr('id'));
});
});
</script>
<div class="gallery sevenspikes-cloudzoom-gallery">
<div class="picture-wrapper">
<div class="picture" id="sevenspikes-cloud-zoom" data-zoomwindowelementid="#Model.ElementId"
data-selectoroftheparentelementofthecloudzoomwindow="#Model.SettingsModel.SelectorOfTheParentElementOfTheCloudZoomWindow"
data-defaultimagecontainerselector="#Model.SettingsModel.DefaultImageContainerSelector">
<a href="#Model.DefaultPicture.FullSizeImageUrl" class="cloud-zoom" id="zoom1" rel="#Model.DefaultPicture.DefaultRelation">
<img src="#Model.DefaultPicture.SmallImageUrl" alt="#Model.DefaultPicture.AlternateText" title="#Model.DefaultPicture.Title" id="cloudZoomImage" itemprop="image" />
</a>
#if (Model.Pictures.Count > 1)
{
<div class="picture-thumbs-navigation-arrow picture-thumbs-prev-arrow">
<span>#T("SevenSpikes.Themes.Uptown.Product.ImageThumbs.Prev")</span>
<img src="#Model.DefaultPicture.TinyImageUrl" data-fullSizeImageUrl="#Model.DefaultPicture.FullSizeImageUrl" alt="Previous" />
</div>
<div class="picture-thumbs-navigation-arrow picture-thumbs-next-arrow">
<span>#T("SevenSpikes.Themes.Uptown.Product.ImageThumbs.Next")</span>
<img src="#Model.DefaultPicture.TinyImageUrl" data-fullSizeImageUrl="#Model.DefaultPicture.FullSizeImageUrl" alt="Next" />
</div>
<div class="picture-thumbs">
#foreach (var picture in Model.Pictures)
{
<a class="cloud-zoom-gallery" href="#picture.FullSizeImageUrl" title="#picture.Title" rel="#picture.GalleryRelation">
<img class="cloud-zoom-gallery-img" src="#picture.TinyImageUrl" alt="#picture.AlternateText" title="#picture.Title" />
</a>
}
</div>
}
</div>
</div>
</div>
}
Any ideas? More files needed to resolve this issue? LMK!
I'm trying to combine the functionality of two buttons into one. This is a program that enables/disables a text or image magnifier. If I enable the zoomer than I want both the text and image to magnify if they are hovered on and vice versa with disable.
How should I edit the function/code to reflect one button that controls the magnification of both image and text?
This is the function I believe is controlling the button and zooming:
$("button").click(function() {
var state = $(this).text(); // enable or disable
$(".zoom:eq(" + $(this).attr('data-id') + ")").anythingZoomer(state);
$(this).text((state === "disable") ? "enable" : "disable");
return false;
});
The full project is below
;
(function(factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof module === 'object' && typeof module.exports === 'object') {
module.exports = factory(require('jquery'));
} else {
factory(jQuery);
}
}(function($) {
"use strict";
$.anythingZoomer = function(el, options) {
var n, o, t, base = this;
base.$wrap = $(el);
base.wrap = el;
// Add a reverse reference to the DOM object
base.$wrap.data('zoomer', base);
base.version = '2.2.6';
base.init = function() {
base.options = o = $.extend({}, $.anythingZoomer.defaultOptions, options);
// default class names
n = $.anythingZoomer.classNames;
// true when small element is showing, false when large is visible
base.state = true;
base.enabled = true;
base.hovered = false;
base.$wrap.addClass(n.wrap).wrapInner('<span class="' + n.wrapInner + '"/>');
base.$inner = base.$wrap.find('.' + n.wrapInner);
base.$small = base.$wrap.find('.' + o.smallArea);
base.$large = base.$wrap.find('.' + o.largeArea);
base.update();
// Add classes after getting size
base.$large.addClass(n.large);
base.$small.addClass(n.small);
base.$inner
.bind('mouseenter' + n.namespace, function() {
if (!base.enabled) {
return;
}
base.saved = base.enabled;
base.hovered = true;
if (o.delay) {
clearTimeout(base.delay);
base.enabled = false;
base.delay = setTimeout(function() {
base.enabled = base.saved;
base.position.type = 'mousemove';
base.$inner.trigger(base.position);
base.reveal();
}, o.delay);
} else {
base.reveal();
}
})
.bind('mouseleave' + n.namespace, function() {
base.hovered = false;
if (!base.enabled) {
return;
}
if (o.delay) {
clearTimeout(base.delay);
base.enabled = base.saved;
}
if (base.state && base.enabled) {
// delay hiding to prevent flash if user hovers over it again
// i.e. moving from a link to the image
base.timer = setTimeout(function() {
if (base.$zoom.hasClass(n.windowed)) {
base.hideZoom(true);
}
}, 200);
}
})
.bind('mousemove' + n.namespace, function(e) {
if (!base.enabled) {
return;
}
base.position = e;
if (!base.hovered) {
return;
}
if (base.state && base.enabled) {
clearTimeout(base.timer);
// get current offsets in case page positioning has changed
// Double demo: expanded text demo will offset image demo zoom window
var off = base.$small.offset();
base.zoomAt(e.pageX - off.left, e.pageY - off.top, null, true);
}
})
.bind(o.switchEvent + (o.switchEvent !== '' ? n.namespace : ''), function() {
if (!base.enabled) {
return;
}
// toggle visible image
if (base.state) {
base.showLarge();
} else {
base.showSmall();
}
});
base.showSmall();
// add events
$.each('initialized zoom unzoom'.split(' '), function(i, f) {
if ($.isFunction(o[f])) {
base.$wrap.bind(f, o[f]);
}
});
base.initialized = true;
base.$wrap.trigger('initialized', base);
};
base.reveal = function() {
base.enabled = base.saved;
if (base.state && base.enabled) {
base.$zoom.stop(true, true).fadeIn(o.speed);
if (o.overlay) {
base.$overlay.addClass(n.overlay);
}
base.$smInner.addClass(n.hovered);
base.$wrap.trigger('zoom', base);
}
};
base.update = function() {
// make sure the large image is hidden
if (base.initialized) {
base.showSmall();
}
base.$smInner = (base.$small.find('.' + n.smallInner).length) ?
base.$small.find('.' + n.smallInner) :
base.$small.wrapInner('<span class="' + n.smallInner + '"/>').find('.' + n.smallInner);
base.$small.find('.' + n.overly).remove();
if (o.clone) {
t = base.$smInner.clone()
.removeAttr('id')
.removeClass(n.smallInner)
.addClass(n.largeInner);
if (base.$large.length) {
// large area exists, just add content
base.$large.html(t.html());
} else {
// no large area, so add it
t.wrap('<div class="' + o.largeArea + '">');
base.$small.after(t.parent());
// set base.$large again in case small area was cloned
base.$large = base.$wrap.find('.' + o.largeArea);
}
}
base.$lgInner = (base.$large.find('.' + n.largeInner).length) ?
base.$large.find('.' + n.largeInner) :
base.$large.wrapInner('<span class="' + n.largeInner + '"/>').find('.' + n.largeInner);
if (!base.$wrap.find('.' + n.zoom).length) {
base.$large.wrap('<div class="' + n.zoom + '"/>');
base.$zoom = base.$wrap.find('.' + n.zoom);
}
if (o.edit && !base.edit) {
base.edit = $('<span class="' + n.edit + '"></span>').appendTo(base.$zoom);
}
// wrap inner content with a span to get a more accurate width
// get height from either the inner content itself or the children of the inner content since span will need
// a "display:block" to get an accurate height, but adding that messes up the width
base.$zoom.show();
base.largeDim = [base.$lgInner.children().width(), Math.max(base.$lgInner.height(), base.$lgInner.children().height())];
base.zoomDim = base.last = [base.$zoom.width(), base.$zoom.height()];
base.$zoom.hide();
base.smallDim = [base.$smInner.children().width(), base.$small.height()];
base.$overlay = $('<div class="' + n.overly + '" style="position:absolute;left:0;top:0;" />').prependTo(base.$small);
base.ratio = [
base.largeDim[0] / (base.smallDim[0] || 1),
base.largeDim[1] / (base.smallDim[1] || 1)
];
base.$inner.add(base.$overlay).css({
width: base.smallDim[0],
height: base.smallDim[1]
});
};
// Show small image - Setup
base.showSmall = function() {
base.state = true;
base.$small.show();
base.$zoom
.removeClass(n.expanded)
.addClass(n.windowed + ' ' + n.zoom)
.css({
width: base.zoomDim[0],
height: base.zoomDim[1]
});
base.$inner.css({
width: base.smallDim[0],
height: base.smallDim[1]
});
};
// Switch small and large on double click
base.showLarge = function() {
base.state = false;
base.$small.hide();
base.$zoom
.stop(true, true)
.fadeIn(o.speed)
.addClass(n.expanded)
.removeClass(n.windowed + ' ' + n.zoom)
.css({
height: 'auto',
width: 'auto'
});
base.$inner.css({
width: base.largeDim[0],
height: base.largeDim[1]
});
base.$large.css({
left: 0,
top: 0,
width: base.largeDim[0],
height: base.largeDim[1]
});
};
// x,y coords -> George Washington in image demo
// base.setTarget( 82, 50, [200,200] );
// 'selector', [xOffset, yOffset], [zoomW, zoomH] -> Aug 26 in calendar demo
// base.setTarget( '.day[rel=2009-08-26]', [0, 0], [200, 200] );
base.setTarget = function(tar, sec, sz) {
var t, x = 0,
y = 0;
clearTimeout(base.timer);
if (!base.$zoom.hasClass(n.windowed)) {
base.showSmall();
}
// x, y coords
if (!isNaN(tar) && !isNaN(sec)) {
x = parseInt(tar, 10);
y = parseInt(sec, 10);
} else if (typeof(tar) === 'string' && $(tar).length) {
// '.selector', [xOffSet, yOffSet]
t = $(tar);
x = t.position().left + t.width() / 2 + (sec ? sec[0] || 0 : 0);
y = t.position().top + t.height() / 2 + (sec ? sec[1] || 0 : 0);
}
base.zoomAt(x, y, sz);
// add overlay
if (o.overlay) {
base.$overlay.addClass(n.overlay);
}
// hovered, but not really
base.$smInner.addClass(n.hovered);
// zoom window triggered
base.$wrap.trigger('zoom', base);
};
// x, y, [zoomX, zoomY] - zoomX, zoomY are the dimensions of the zoom window
base.zoomAt = function(x, y, sz, internal) {
var sx = (sz ? sz[0] || 0 : 0) || base.last[0],
sy = (sz ? sz[1] || sz[0] || 0 : 0) || base.last[1],
sx2 = sx / 2,
sy2 = sy / 2,
ex = o.edge || (o.edge === 0 ? 0 : sx2 * 0.66), // 2/3 of zoom window
ey = o.edge || (o.edge === 0 ? 0 : sy2 * 0.66), // allows edge to be zero
m = parseInt(base.$inner.css('margin-left'), 10) || base.$inner.position().left || 0;
// save new zoom size
base.last = [sx, sy];
// save x, y for external access
base.current = [x, y];
// show coordinates
if (o.edit) {
base.edit.html(Math.round(x) + ', ' + Math.round(y));
}
if ((x < -ex) || (x > base.smallDim[0] + ex) || (y < -ey) || (y > base.smallDim[1] + ey)) {
base.hideZoom(internal);
return;
} else {
// Sometimes the mouseenter event is delayed
base.$zoom.stop(true, true).fadeIn(o.speed);
}
// center zoom under the cursor
base.$zoom.css({
left: x - sx2 + m,
top: y - sy2,
width: sx,
height: sy
});
// match locations of small element to the large
base.$large.css({
left: -(x - o.offsetX - sx2 / 2) * base.ratio[0],
top: -(y - o.offsetY - sy2 / 2) * base.ratio[1]
});
};
base.hideZoom = function(internal) {
if (internal && base.$smInner.hasClass(n.hovered)) {
base.$wrap.trigger('unzoom', base);
}
base.last = base.zoomDim;
base.$zoom.stop(true, true).fadeOut(o.speed);
base.$overlay.removeClass(n.overlay);
base.$smInner.removeClass(n.hovered);
base.lastKey = null;
};
base.setEnabled = function(enable) {
base.enabled = enable;
if (enable) {
var off = base.$small.offset();
base.zoomAt(base.position.pageX - off.left, base.position.pageY - off.top, null, true);
} else {
base.showSmall();
base.hideZoom();
base.hovered = false;
}
};
// Initialize zoomer
base.init();
};
// class names used by anythingZoomer
$.anythingZoomer.classNames = {
namespace: '.anythingZoomer', // event namespace
wrap: 'az-wrap',
wrapInner: 'az-wrap-inner',
large: 'az-large',
largeInner: 'az-large-inner',
small: 'az-small',
smallInner: 'az-small-inner',
overlay: 'az-overlay', // toggled class name
overly: 'az-overly', // overlay unstyled class
hovered: 'az-hovered',
zoom: 'az-zoom',
windowed: 'az-windowed', // zoom window active
expanded: 'az-expanded', // zoom window inactive (large is showing)
edit: 'az-coords', // coordinate window
scrollzoom: 'az-scrollzoom'
};
$.anythingZoomer.defaultOptions = {
// content areas
smallArea: 'small', // class of small content area; the element with this class name must be inside of the wrapper
largeArea: 'large', // class of large content area; this class must exist inside of the wrapper. When the clone option is true, it will add this automatically
clone: false, // Make a clone of the small content area, use css to modify the style
// appearance
overlay: false, // set to true to apply overlay class "az-overlay"; false to not apply it
speed: 100, // fade animation speed (in milliseconds)
edge: 30, // How far outside the wrapped edges the mouse can go; previously called "expansionSize"
offsetX: 0, // adjust the horizontal position of the large content inside the zoom window as desired
offsetY: 0, // adjust the vertical position of the large content inside the zoom window as desired
// functionality
switchEvent: 'dblclick', // event that allows toggling between small and large elements - default is double click
delay: 0, // time to delay before revealing the zoom window.
// edit mode
edit: false // add x,y coordinates into zoom window to make it easier to find coordinates
};
$.fn.anythingZoomer = function(options, second, sx, sy) {
return this.each(function() {
var anyZoom = $(this).data('zoomer');
// initialize the zoomer but prevent multiple initializations
if (/object|undefined/.test(typeof options)) {
if (anyZoom) {
anyZoom.update();
} else {
(new $.anythingZoomer(this, options));
}
} else if (anyZoom && (typeof options === 'string' || (!isNaN(options) && !isNaN(second)))) {
if (/(en|dis)able/.test(options)) {
anyZoom.setEnabled(options === 'enable');
} else {
anyZoom.setTarget(options, second, sx, sy);
}
}
});
};
$.fn.getAnythingZoomer = function() {
return this.data('zoomer');
};
return $.anythingzoomer;
}));
/* AnythingZoomer */
.az-wrap,
.az-small,
.az-large {
position: relative;
}
.az-wrap-inner {
display: block;
margin: 0 auto;
/* center small & large content */
}
/* This wraps the large image and hides it */
.az-zoom {
background: #fff;
border: #333 1px solid;
position: absolute;
top: 0;
left: 0;
width: 150px;
height: 150px;
overflow: hidden;
z-index: 100;
display: none;
-moz-box-shadow: inset 0px 0px 4px #000;
-webkit-box-shadow: inset 0px 0px 4px #000;
box-shadow: inset 0px 0px 4px #000;
}
/* Class applied to az-mover when large image is windowed */
.az-windowed {
overflow: hidden;
position: absolute;
}
/* Class applied to az-mover when large image is fully shown */
.az-expanded {
height: auto;
width: auto;
position: static;
overflow: visible;
}
/* overlay small area */
.az-overlay {
background-color: #000;
opacity: 0.3;
filter: alpha(opacity=30);
z-index: 10;
}
/* edit mode coordinate styling */
.az-coords {
display: none;
/* hidden when expanded */
}
.az-zoom .az-coords {
display: block;
position: absolute;
top: 0;
right: 0;
background: #000;
background: rgba(0, 0, 0, 0.5);
color: #fff;
}
/* ZOOM CONTAINER */
.zoom {
display: block;
margin: 0 auto;
}
.large {
background: white;
}
/* FOR TEXT DEMO */
.small p {
font-size: 16px;
width: 700px
}
.large p {
font-size: 32px;
width: 1400px;
}
/* FOR IMAGE DEMO */
.small img {
width: 250px;
}
.large img {
width: 500px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Image and Text Magnifier</title>
<!-- anythingZoomer required -->
<link rel="stylesheet" href="css/anythingzoomer.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="js/jquery.anythingzoomer.js"></script>
<script>
$(function() {
// clone the text
$(".zoom:first").anythingZoomer({
clone: true
});
$(".zoom:last").anythingZoomer();
$("button").click(function() {
var state = $(this).text(); // enable or disable
$(".zoom:eq(" + $(this).attr('data-id') + ")").anythingZoomer(state);
$(this).text((state === "disable") ? "enable" : "disable");
return false;
});
});
</script>
</head>
<body id="double">
<div id="main-content">
<p>Double click within the section to toggle between the large and small versions.</p>
<p><strong>Text Demo <button data-id="0">disable</button></strong></p>
<div class="zoom">
<div class="small">
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae
est. Mauris placerat eleifend leo.</p>
</div>
<!-- the clone option will automatically make a div.large if it doesn't exist -->
</div>
<br>
<p><strong>Image Demo <button data-id="1">disable</button></strong></p>
<div class="zoom second">
<div class="small">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/f3/Dean_Franklin_-_06.04.03_Mount_Rushmore_Monument_%28by-sa%29-3_new.jpg/1200px-Dean_Franklin_-_06.04.03_Mount_Rushmore_Monument_%28by-sa%29-3_new.jpg" alt="small rushmore">
</div>
<div class="large">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/f3/Dean_Franklin_-_06.04.03_Mount_Rushmore_Monument_%28by-sa%29-3_new.jpg/1200px-Dean_Franklin_-_06.04.03_Mount_Rushmore_Monument_%28by-sa%29-3_new.jpg" alt="big rushmore">
</div>
</div>
</div>
</body>
</html>
This works! Just loop through each of the elements using .each and then add the scroll zoomer function to it.when the button is pressed, loop through the elements again and apply the toggle functionality.
;
(function(factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof module === 'object' && typeof module.exports === 'object') {
module.exports = factory(require('jquery'));
} else {
factory(jQuery);
}
}(function($) {
"use strict";
$.anythingZoomer = function(el, options) {
var n, o, t, base = this;
base.$wrap = $(el);
base.wrap = el;
// Add a reverse reference to the DOM object
base.$wrap.data('zoomer', base);
base.version = '2.2.6';
base.init = function() {
base.options = o = $.extend({}, $.anythingZoomer.defaultOptions, options);
// default class names
n = $.anythingZoomer.classNames;
// true when small element is showing, false when large is visible
base.state = true;
base.enabled = true;
base.hovered = false;
base.$wrap.addClass(n.wrap).wrapInner('<span class="' + n.wrapInner + '"/>');
base.$inner = base.$wrap.find('.' + n.wrapInner);
base.$small = base.$wrap.find('.' + o.smallArea);
base.$large = base.$wrap.find('.' + o.largeArea);
base.update();
// Add classes after getting size
base.$large.addClass(n.large);
base.$small.addClass(n.small);
base.$inner
.bind('mouseenter' + n.namespace, function() {
if (!base.enabled) {
return;
}
base.saved = base.enabled;
base.hovered = true;
if (o.delay) {
clearTimeout(base.delay);
base.enabled = false;
base.delay = setTimeout(function() {
base.enabled = base.saved;
base.position.type = 'mousemove';
base.$inner.trigger(base.position);
base.reveal();
}, o.delay);
} else {
base.reveal();
}
})
.bind('mouseleave' + n.namespace, function() {
base.hovered = false;
if (!base.enabled) {
return;
}
if (o.delay) {
clearTimeout(base.delay);
base.enabled = base.saved;
}
if (base.state && base.enabled) {
// delay hiding to prevent flash if user hovers over it again
// i.e. moving from a link to the image
base.timer = setTimeout(function() {
if (base.$zoom.hasClass(n.windowed)) {
base.hideZoom(true);
}
}, 200);
}
})
.bind('mousemove' + n.namespace, function(e) {
if (!base.enabled) {
return;
}
base.position = e;
if (!base.hovered) {
return;
}
if (base.state && base.enabled) {
clearTimeout(base.timer);
// get current offsets in case page positioning has changed
// Double demo: expanded text demo will offset image demo zoom window
var off = base.$small.offset();
base.zoomAt(e.pageX - off.left, e.pageY - off.top, null, true);
}
})
.bind(o.switchEvent + (o.switchEvent !== '' ? n.namespace : ''), function() {
if (!base.enabled) {
return;
}
// toggle visible image
if (base.state) {
base.showLarge();
} else {
base.showSmall();
}
});
base.showSmall();
// add events
$.each('initialized zoom unzoom'.split(' '), function(i, f) {
if ($.isFunction(o[f])) {
base.$wrap.bind(f, o[f]);
}
});
base.initialized = true;
base.$wrap.trigger('initialized', base);
};
base.reveal = function() {
base.enabled = base.saved;
if (base.state && base.enabled) {
base.$zoom.stop(true, true).fadeIn(o.speed);
if (o.overlay) {
base.$overlay.addClass(n.overlay);
}
base.$smInner.addClass(n.hovered);
base.$wrap.trigger('zoom', base);
}
};
base.update = function() {
// make sure the large image is hidden
if (base.initialized) {
base.showSmall();
}
base.$smInner = (base.$small.find('.' + n.smallInner).length) ?
base.$small.find('.' + n.smallInner) :
base.$small.wrapInner('<span class="' + n.smallInner + '"/>').find('.' + n.smallInner);
base.$small.find('.' + n.overly).remove();
if (o.clone) {
t = base.$smInner.clone()
.removeAttr('id')
.removeClass(n.smallInner)
.addClass(n.largeInner);
if (base.$large.length) {
// large area exists, just add content
base.$large.html(t.html());
} else {
// no large area, so add it
t.wrap('<div class="' + o.largeArea + '">');
base.$small.after(t.parent());
// set base.$large again in case small area was cloned
base.$large = base.$wrap.find('.' + o.largeArea);
}
}
base.$lgInner = (base.$large.find('.' + n.largeInner).length) ?
base.$large.find('.' + n.largeInner) :
base.$large.wrapInner('<span class="' + n.largeInner + '"/>').find('.' + n.largeInner);
if (!base.$wrap.find('.' + n.zoom).length) {
base.$large.wrap('<div class="' + n.zoom + '"/>');
base.$zoom = base.$wrap.find('.' + n.zoom);
}
if (o.edit && !base.edit) {
base.edit = $('<span class="' + n.edit + '"></span>').appendTo(base.$zoom);
}
// wrap inner content with a span to get a more accurate width
// get height from either the inner content itself or the children of the inner content since span will need
// a "display:block" to get an accurate height, but adding that messes up the width
base.$zoom.show();
base.largeDim = [base.$lgInner.children().width(), Math.max(base.$lgInner.height(), base.$lgInner.children().height())];
base.zoomDim = base.last = [base.$zoom.width(), base.$zoom.height()];
base.$zoom.hide();
base.smallDim = [base.$smInner.children().width(), base.$small.height()];
base.$overlay = $('<div class="' + n.overly + '" style="position:absolute;left:0;top:0;" />').prependTo(base.$small);
base.ratio = [
base.largeDim[0] / (base.smallDim[0] || 1),
base.largeDim[1] / (base.smallDim[1] || 1)
];
base.$inner.add(base.$overlay).css({
width: base.smallDim[0],
height: base.smallDim[1]
});
};
// Show small image - Setup
base.showSmall = function() {
base.state = true;
base.$small.show();
base.$zoom
.removeClass(n.expanded)
.addClass(n.windowed + ' ' + n.zoom)
.css({
width: base.zoomDim[0],
height: base.zoomDim[1]
});
base.$inner.css({
width: base.smallDim[0],
height: base.smallDim[1]
});
};
// Switch small and large on double click
base.showLarge = function() {
base.state = false;
base.$small.hide();
base.$zoom
.stop(true, true)
.fadeIn(o.speed)
.addClass(n.expanded)
.removeClass(n.windowed + ' ' + n.zoom)
.css({
height: 'auto',
width: 'auto'
});
base.$inner.css({
width: base.largeDim[0],
height: base.largeDim[1]
});
base.$large.css({
left: 0,
top: 0,
width: base.largeDim[0],
height: base.largeDim[1]
});
};
// x,y coords -> George Washington in image demo
// base.setTarget( 82, 50, [200,200] );
// 'selector', [xOffset, yOffset], [zoomW, zoomH] -> Aug 26 in calendar demo
// base.setTarget( '.day[rel=2009-08-26]', [0, 0], [200, 200] );
base.setTarget = function(tar, sec, sz) {
var t, x = 0,
y = 0;
clearTimeout(base.timer);
if (!base.$zoom.hasClass(n.windowed)) {
base.showSmall();
}
// x, y coords
if (!isNaN(tar) && !isNaN(sec)) {
x = parseInt(tar, 10);
y = parseInt(sec, 10);
} else if (typeof(tar) === 'string' && $(tar).length) {
// '.selector', [xOffSet, yOffSet]
t = $(tar);
x = t.position().left + t.width() / 2 + (sec ? sec[0] || 0 : 0);
y = t.position().top + t.height() / 2 + (sec ? sec[1] || 0 : 0);
}
base.zoomAt(x, y, sz);
// add overlay
if (o.overlay) {
base.$overlay.addClass(n.overlay);
}
// hovered, but not really
base.$smInner.addClass(n.hovered);
// zoom window triggered
base.$wrap.trigger('zoom', base);
};
// x, y, [zoomX, zoomY] - zoomX, zoomY are the dimensions of the zoom window
base.zoomAt = function(x, y, sz, internal) {
var sx = (sz ? sz[0] || 0 : 0) || base.last[0],
sy = (sz ? sz[1] || sz[0] || 0 : 0) || base.last[1],
sx2 = sx / 2,
sy2 = sy / 2,
ex = o.edge || (o.edge === 0 ? 0 : sx2 * 0.66), // 2/3 of zoom window
ey = o.edge || (o.edge === 0 ? 0 : sy2 * 0.66), // allows edge to be zero
m = parseInt(base.$inner.css('margin-left'), 10) || base.$inner.position().left || 0;
// save new zoom size
base.last = [sx, sy];
// save x, y for external access
base.current = [x, y];
// show coordinates
if (o.edit) {
base.edit.html(Math.round(x) + ', ' + Math.round(y));
}
if ((x < -ex) || (x > base.smallDim[0] + ex) || (y < -ey) || (y > base.smallDim[1] + ey)) {
base.hideZoom(internal);
return;
} else {
// Sometimes the mouseenter event is delayed
base.$zoom.stop(true, true).fadeIn(o.speed);
}
// center zoom under the cursor
base.$zoom.css({
left: x - sx2 + m,
top: y - sy2,
width: sx,
height: sy
});
// match locations of small element to the large
base.$large.css({
left: -(x - o.offsetX - sx2 / 2) * base.ratio[0],
top: -(y - o.offsetY - sy2 / 2) * base.ratio[1]
});
};
base.hideZoom = function(internal) {
if (internal && base.$smInner.hasClass(n.hovered)) {
base.$wrap.trigger('unzoom', base);
}
base.last = base.zoomDim;
base.$zoom.stop(true, true).fadeOut(o.speed);
base.$overlay.removeClass(n.overlay);
base.$smInner.removeClass(n.hovered);
base.lastKey = null;
};
base.setEnabled = function(enable) {
base.enabled = enable;
if (enable) {
var off = base.$small.offset();
base.zoomAt(base.position.pageX - off.left, base.position.pageY - off.top, null, true);
} else {
base.showSmall();
base.hideZoom();
base.hovered = false;
}
};
// Initialize zoomer
base.init();
};
// class names used by anythingZoomer
$.anythingZoomer.classNames = {
namespace: '.anythingZoomer', // event namespace
wrap: 'az-wrap',
wrapInner: 'az-wrap-inner',
large: 'az-large',
largeInner: 'az-large-inner',
small: 'az-small',
smallInner: 'az-small-inner',
overlay: 'az-overlay', // toggled class name
overly: 'az-overly', // overlay unstyled class
hovered: 'az-hovered',
zoom: 'az-zoom',
windowed: 'az-windowed', // zoom window active
expanded: 'az-expanded', // zoom window inactive (large is showing)
edit: 'az-coords', // coordinate window
scrollzoom: 'az-scrollzoom'
};
$.anythingZoomer.defaultOptions = {
// content areas
smallArea: 'small', // class of small content area; the element with this class name must be inside of the wrapper
largeArea: 'large', // class of large content area; this class must exist inside of the wrapper. When the clone option is true, it will add this automatically
clone: false, // Make a clone of the small content area, use css to modify the style
// appearance
overlay: false, // set to true to apply overlay class "az-overlay"; false to not apply it
speed: 100, // fade animation speed (in milliseconds)
edge: 30, // How far outside the wrapped edges the mouse can go; previously called "expansionSize"
offsetX: 0, // adjust the horizontal position of the large content inside the zoom window as desired
offsetY: 0, // adjust the vertical position of the large content inside the zoom window as desired
// functionality
switchEvent: 'dblclick', // event that allows toggling between small and large elements - default is double click
delay: 0, // time to delay before revealing the zoom window.
// edit mode
edit: false // add x,y coordinates into zoom window to make it easier to find coordinates
};
$.fn.anythingZoomer = function(options, second, sx, sy) {
return this.each(function() {
var anyZoom = $(this).data('zoomer');
// initialize the zoomer but prevent multiple initializations
if (/object|undefined/.test(typeof options)) {
if (anyZoom) {
anyZoom.update();
} else {
(new $.anythingZoomer(this, options));
}
} else if (anyZoom && (typeof options === 'string' || (!isNaN(options) && !isNaN(second)))) {
if (/(en|dis)able/.test(options)) {
anyZoom.setEnabled(options === 'enable');
} else {
anyZoom.setTarget(options, second, sx, sy);
}
}
});
};
$.fn.getAnythingZoomer = function() {
return this.data('zoomer');
};
return $.anythingzoomer;
}));
/* AnythingZoomer */
.az-wrap,
.az-small,
.az-large {
position: relative;
}
.az-wrap-inner {
display: block;
margin: 0 auto;
/* center small & large content */
}
/* This wraps the large image and hides it */
.az-zoom {
background: #fff;
border: #333 1px solid;
position: absolute;
top: 0;
left: 0;
width: 150px;
height: 150px;
overflow: hidden;
z-index: 100;
display: none;
-moz-box-shadow: inset 0px 0px 4px #000;
-webkit-box-shadow: inset 0px 0px 4px #000;
box-shadow: inset 0px 0px 4px #000;
}
/* Class applied to az-mover when large image is windowed */
.az-windowed {
overflow: hidden;
position: absolute;
}
/* Class applied to az-mover when large image is fully shown */
.az-expanded {
height: auto;
width: auto;
position: static;
overflow: visible;
}
/* overlay small area */
.az-overlay {
background-color: #000;
opacity: 0.3;
filter: alpha(opacity=30);
z-index: 10;
}
/* edit mode coordinate styling */
.az-coords {
display: none;
/* hidden when expanded */
}
.az-zoom .az-coords {
display: block;
position: absolute;
top: 0;
right: 0;
background: #000;
background: rgba(0, 0, 0, 0.5);
color: #fff;
}
/* ZOOM CONTAINER */
.zoom {
display: block;
margin: 0 auto;
}
.large {
background: white;
}
/* FOR TEXT DEMO */
.small p {
font-size: 16px;
width: 700px
}
.large p {
font-size: 32px;
width: 1400px;
}
/* FOR IMAGE DEMO */
.small img {
width: 250px;
}
.large img {
width: 500px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Image and Text Magnifier</title>
<!-- anythingZoomer required -->
<link rel="stylesheet" href="css/anythingzoomer.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="js/jquery.anythingzoomer.js"></script>
<script>
$(function() {
// clone the text
$(".zoom").each(function(){
$(this).anythingZoomer({clone: true});
});
$("button").click(function() {
var state = $(this).text(); // enable or disable
$(".zoom").each(function(){
$(this).anythingZoomer(state);
});
$(this).text((state === "disable") ? "enable" : "disable");
return false;
});
});
</script>
</head>
<body id="double">
<div id="main-content">
<p>Double click within the section to toggle between the large and small versions.</p>
<p><button>disable</button></p>
<p><strong>Text Demo </strong></p>
<div class="zoom">
<div class="small">
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae
est. Mauris placerat eleifend leo.</p>
</div>
<!-- the clone option will automatically make a div.large if it doesn't exist -->
</div>
<br>
<p><strong>Image Demo
<div class="zoom second">
<div class="small">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/f3/Dean_Franklin_-_06.04.03_Mount_Rushmore_Monument_%28by-sa%29-3_new.jpg/1200px-Dean_Franklin_-_06.04.03_Mount_Rushmore_Monument_%28by-sa%29-3_new.jpg" alt="small rushmore">
</div>
<div class="large">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/f3/Dean_Franklin_-_06.04.03_Mount_Rushmore_Monument_%28by-sa%29-3_new.jpg/1200px-Dean_Franklin_-_06.04.03_Mount_Rushmore_Monument_%28by-sa%29-3_new.jpg" alt="big rushmore">
</div>
</div>
</div>
</body>
</html>
Didn't read the code but you could create the zoom using CSS
btn:hover element{
font-size:larger;
}
How can I stop this carousel from bubbling the animation? If you click right faster, it will start to mix up things. I need to stop the event handler function if the animation is running, inside that timeOut, the handlers should go offline.
Please see snippet below:
var Carousel = function(element, options) {
this.carousel = document.querySelector(element);
this.slides = Array.prototype.slice.call(this.carousel.querySelectorAll('.item'), null);
this.prev = this.carousel.querySelector("[data-slide='prev']");
this.next = this.carousel.querySelector("[data-slide='next']");
this.indicators = this.carousel.querySelectorAll(".carousel-indicators li");
this.interval = options && options.interval ? options.interval : 5000;
this.duration = 600; // bootstrap carousel default transition duration
this.paused = null;
this.direction = null;
this.index = 0;
this.total = this.slides.length;
this.init();
};
Carousel.prototype = {
init: function() {
this.cycle();
this.actions();
},
_slideTo: function(next, e) {
var self = this;
//determine type
var active = self._getActiveIndex(); // the current active
var direction = self.direction;
var type = direction === 'left' ? 'next' : 'prev';
if (!this.slides[next].classList.contains(type)) {
//e.preventDefault();
//e.defaultPrevented = false;
this.slides[next].classList.add(type);
this.slides[next].offsetWidth;
this.slides[active].classList.add(direction);
this.slides[next].classList.add(direction);
setTimeout(function() {
console.log('inside timeout prevented? ' + e.defaultPrevented);
self.slides[next].classList.remove(type, direction);
self.slides[next].classList.add('active');
self.slides[active].classList.remove('active', direction);
self._curentPage(self.indicators[next]);
//e.defaultPrevented = false;
}, self.duration + 200);
}
},
_getActiveIndex: function() {
return this._getItemIndex('.item.active')
},
_getItemIndex: function(itm) {
return this.slides.indexOf(this.carousel.querySelector(itm))
},
_curentPage: function(p) {
for (var i = 0; i < this.indicators.length; ++i) {
var a = this.indicators[i];
a.className = "";
}
p.className = "active";
},
cycle: function() {
var self = this;
//deleted some shit
},
actions: function() {
var self = this;
self.next.addEventListener("click", function(e) {
e.preventDefault();
self.index++;
self.direction = 'left'; //set direction first
if (self.index == self.total - 1) {
self.index = self.total - 1;
} else if (self.index == self.total) {
self.index = 0
}
self._slideTo(self.index, e);
}, false);
self.prev.addEventListener("click", function(e) {
e.preventDefault();
self.index--;
self.direction = 'right'; //set direction first
if (self.index == 0) {
self.index = 0;
} else if (self.index < 0) {
self.index = self.total - 1
}
self._slideTo(self.index, e);
}, false);
for (var i = 0; i < self.indicators.length; ++i) {
var a = self.indicators[i];
a.addEventListener("click", function(e) {
e.preventDefault();
var n = parseInt(this.getAttribute("data-slide-to"), 10);
self.index = n;
if (self.index == 0) {
self.index = 0;
}
if (self.index > 0) {}
if (self.index == self.total - 1) {
self.index = self.total - 1;
} else {}
//determine direction first
var active = self._getActiveIndex(); // the current active
if ((active < self.index) || (active === self.total - 1 && self.index === 0)) {
self.direction = 'left'; // next
} else if ((active > self.index) || (active === 0 && self.index === self.total - 1)) {
self.direction = 'right'; // prev
}
self._slideTo(self.index, e);
}, false);
}
window.addEventListener('keydown', function(e) {
if (/input|textarea/i.test(e.target.tagName)) return;
switch (e.which) {
case 39:
self.index++;
self.direction = 'left';
if (self.index == self.total - 1) {
self.index = self.total - 1;
} else
if (self.index == self.total) {
self.index = 0
}
break;
case 37:
self.index--;
self.direction = 'right';
if (self.index == 0) {
self.index = 0;
} else
if (self.index < 0) {
self.index = self.total - 1
}
break;
default:
return;
}
// e.preventDefault();
self._slideTo(self.index, e);
}, false)
}
}
var slider = new Carousel("#myCarousel1");
#myCarousel1 {
height: 300px;
max-width: 100%
}
.item {
height: 300px;
background: url(http://placehold.it/100x100/069/069.png) repeat center center;
background-size: cover
}
<link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet" />
<div id="myCarousel1" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
<li data-target="#myCarousel1" data-slide-to="0" class="active"></li>
<li data-target="#myCarousel1" data-slide-to="1"></li>
<li data-target="#myCarousel1" data-slide-to="2"></li>
</ol>
<div class="carousel-inner">
<div class="item active">
<div class="container">
<div class="carousel-caption">
<h1>Example headline.</h1>
<p>Note: If you're viewing this page via a <code>file://</code> URL, the "next" and "previous" Glyphicon buttons on the left and right might not load/display properly due to web browser security rules.</p>
<p><a class="btn btn-lg btn-primary" href="#" role="button">Sign up today</a>
</p>
</div>
</div>
</div>
<div class="item">
<div class="container">
<div class="carousel-caption">
<h1>Another example headline.</h1>
<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
<p><a class="btn btn-lg btn-primary" href="#" role="button">Learn more</a>
</p>
</div>
</div>
</div>
<div class="item">
<div class="container">
<div class="carousel-caption">
<h1>One more for good measure.</h1>
<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
<p><a class="btn btn-lg btn-primary" href="#" role="button">Browse gallery</a>
</p>
</div>
</div>
</div>
</div>
<span class="glyphicon glyphicon-chevron-left"></span>
<span class="glyphicon glyphicon-chevron-right"></span>
</div>
Perhaps checking the time interval between the clicks and returning false from the function that slides the carousel can solve this problem:
var oldTs = 0;
element.removeEventListener("click", slideClickHandler);
function slideClickHandler(e) {
var ts = e.timeStamp;
if ((oldTs !== 0) && (ts - oldTs < 500)) return false; //If time between clicks is 500 miliseconds and its not the first click cancel slide
else {
oldTs = ts; //Update timestamp buffer
slide(); //Do the sliding stuff
}
}
element.addEventListener('click', slideClickHandler);
Edit: You should put this code in a function and refresh the click handler after every slide for it to work.