Related
class CVP {
constructor(obj) {
const { P, V, PC, BPB, MPB, VRC, VBC, FS, PROG, PROGC, TW, TC } = obj;
// player
this.player = document.querySelector(P);
// video el
this.video = document.querySelector(V);
// player controller
this.playerController = document.querySelector(PC);
// play controlers
this.bigPlayBtn = document.querySelector(BPB);
this.miniPlayBtn = document.querySelector(MPB);
// volume controllers
this.volumeRangeController = document.querySelector(VRC);
this.volumeBtnController = document.querySelector(VBC);
// fullscreen
this.fullscreen = document.querySelector(FS);
// progress bar
this.progress = document.querySelector(PROG);
this.progressCurr = document.querySelector(PROGC);
// time displayers
this.timeWhole = document.querySelector(TW);
this.timeCurr = document.querySelector(TC);
// bool vars
this.isMousedown = false;
this.isFullScreen = false;
// timer vars
this.timer = '';
this.timerTime = 1000;
}
setIsMouseDown = () => {
this.isMousedown = !this.isMousedown;
};
bigPlayBtnHandler = () => {
this.bigPlayBtn.classList.toggle('HideBigPlayBtn');
};
showHideControlls = () => {
this.player.classList.toggle('paused');
};
static changeIcon(target, remove, add) {
target.classList.remove(remove);
target.classList.add(add);
}
changePlayIcon() {
console.log(this.video.src);
const target = this.miniPlayBtn;
let icon = this.video.paused ? 'play' : 'pause';
if (icon === 'pause') {
CVP.changeIcon(target, 'play', 'pause');
} else {
CVP.changeIcon(target, 'pause', 'play');
}
}
changeVolumeIcon(volElIconID) { // not in use
const target = document.querySelector(volElIconID);
if (this.video.muted) {
CVP.changeIcon(target, 'max', 'mute');
} else {
CVP.changeIcon(target, 'mute', 'max');
}
}
handleVideoTime(time) {
// minutes and seconds So Far
let hours;
let min = Math.floor(time / 60);
let sec = Math.floor(time % 60);
let output = '';
sec = (sec < 10) ? sec = `0${sec}` : sec;
min = (min < 10) ? min = `0${min}` : min;
output = `${min}:${sec}`;
return output;
}
rangeVolumeController() {
cvp.video[this.name] = this.value;
if (cvp.volumeRangeController.value == 0) {
cvp.video.muted = true;
CVP.changeIcon(cvp.volumeBtnController, 'max', 'mute');
} else {
cvp.video.muted = false;
CVP.changeIcon(cvp.volumeBtnController, 'mute', 'max');
}
}
btnVolumeController() {
if (cvp.video.muted) {
cvp.video.muted = false;
CVP.changeIcon(cvp.volumeBtnController, 'mute', 'max');
cvp.volumeRangeController.value = 1;
cvp.video.volume = 1;
} else {
cvp.video.muted = true;
CVP.changeIcon(cvp.volumeBtnController, 'max', 'mute');
cvp.volumeRangeController.value = 0;
}
}
hideWhenFullScreen() {
if (this.isFullScreen) {
this.playerController.hidden = false; // or this.playerController.style.bottom = '0px';
document.body.style.cursor = 'auto';
clearTimeout(this.timer);
this.timer = setTimeout(() => {
this.playerController.hidden = true; // or this.playerController.style.bottom = '-50px';
document.body.style.cursor = 'none';
}, this.timerTime);
} else {
this.playerController.hidden = false; // or this.playerController.style.bottom = '0px';
document.body.style.cursor = 'auto';
}
}
toggleFullScreen() {
if (this.isFullScreen) {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
} else {
console.error('Unable to find a fullscreen exit method.');
}
} else {
if (this.player.requestFullscreen) {
this.player.requestFullscreen();
} // standard
else if (this.player.webkitRequestFullscreen) {
this.player.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
} else if (this.player.mozRequestFullScreen) {
this.player.mozRequestFullScreen();
} else if (this.player.msRequestFullscreen) {
this.player.msRequestFullscreen();
} else {
console.error('Unable to find a fullscreen request method');
}
}
}
toggleFullScreenHelper() {
this.player.classList.toggle('isFullScreen');
this.isFullScreen = !this.isFullScreen;
}
togglePlay() {
const action = this.video.paused ? 'play' : 'pause';
this.video[action]();
this.playerController.style.bottom = '0px';
this.changePlayIcon();
this.showHideControlls();
}
showVideoTime() {
const {
currentTime,
duration
} = cvp.video;
const pct = (currentTime / duration) * 100;
cvp.progressCurr.style.width = pct + '%';
cvp.timeCurr.innerText = cvp.handleVideoTime(currentTime.toFixed(0));
cvp.timeWhole.innerText = cvp.handleVideoTime(duration);
}
scrub(e) {
console.log(e);
console.log('e', e, 'this', this);
let seconds = (e.offsetX / this.progress.offsetWidth) * this.video.duration;
this.video.currentTime = seconds;
}
loadVideo() {
// il metodo รจ da applciare assieme a un loader e ad altre gestioni degli eventi video
// esempi di loader: https://www.w3schools.com/howto/howto_css_loader.asp
// metodi video: https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/loadeddata_event
// per i tooltips: https://www.w3schools.com/howto/howto_css_tooltip.asp
console.log(this.video.src);
}
init() {
// Hook up the Event Listeners
// toggle Play
this.video.addEventListener('click', this.togglePlay.bind(this));
this.miniPlayBtn.addEventListener('click', this.togglePlay.bind(this));
this.bigPlayBtn.addEventListener('click', this.togglePlay.bind(this));
this.video.addEventListener('loadeddata', this.loadVideo.bind(this));
// bigPlayBtn show/hide handler
this.video.addEventListener('click', this.bigPlayBtnHandler);
this.bigPlayBtn.addEventListener('click', this.bigPlayBtnHandler);
this.miniPlayBtn.addEventListener('click', this.bigPlayBtnHandler);
// time update
this.video.addEventListener('timeupdate', this.showVideoTime);
// progress bar events
this.progress.addEventListener('click', this.scrub.bind(this));
this.progress.addEventListener('mousemove', (e) => this.isMousedown && this.scrub(e));
this.progress.addEventListener('mousedown', this.setIsMouseDown);
this.progress.addEventListener('mouseup', this.setIsMouseDown);
// fullscreen
this.fullscreen.addEventListener('click', this.toggleFullScreen.bind(this));
// volume controllers
this.volumeBtnController.addEventListener('click', this.btnVolumeController);
this.volumeRangeController.addEventListener('change', this.rangeVolumeController);
this.volumeRangeController.addEventListener('mousemove', this.rangeVolumeController);
// cross-browser fullscreen hanlder
const browsersFullScreen = [
'fullscreenchange',
'mozfullscreenchange',
'webkitfullscreenchange',
'msfullscreenchange',
];
browsersFullScreen.forEach(browser => document.addEventListener(browser, this.toggleFullScreenHelper.bind(this)));
// player show/hide controlls on mousemove event
this.player.addEventListener('mousemove', this.hideWhenFullScreen.bind(this));
}
}
const initializeCVP = {
P: '.CVP',
V: '.video',
PC: '.playerController',
BPB: '.bigPlayBtn',
MPB: '.miniPlayBtn',
VRC: '.volumeRC',
VBC: '.volumeBC',
FS: '.fullscreen',
PROG: '.progress',
PROGC: '.progressCurr',
TW: '.timeWhole',
TC: '.timeCurr',
};
let cvp = new CVP(initializeCVP);
cvp.init();
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
display: flex;
flex-direction: column;
justify-content: center;
align-content: center;
align-items: center;
height: 100vh;
background-image: linear-gradient(to top, #dad4ec 0%, #dad4ec 1%, #f3e7e9 100%);
/* background-image: linear-gradient(-20deg, #f794a4 0%, #fdd6bd 100%); */
}
[hidden] {
display: none !important;
}
.player {
display: flex;
justify-content: center;
border-radius: 10px;
width: 700px;
max-height: 100%;
position: relative;
font-size: 16px;
overflow: hidden;
text-align: center;
background: #000;
color: #fff;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.4), 0 10px 20px -3px rgba(0, 0, 0, 0.2);
margin-bottom: 5vh;
}
/* This css is only applied when fullscreen is active. */
.player.isFullScreen {
max-width: none;
max-height: none;
width: 100%;
height: 100%;
background: #000;
}
.player.isFullScreen video {
width: 100%;
height: auto;
}
.video {
max-width: 100%;
max-height: 100%;
-o-object-fit: fill;
object-fit: fill;
/* These are the actual dimensions of the video. Avoid the awkward element resize after the video loads. */
/* width: 640px;
height: 358px; */
}
.playerController {
display: flex;
align-items: center;
justify-content: space-evenly;
width: 98%;
max-width: 1000px;
/* limiting in fullscreen mode */
position: absolute;
background: rgba(51, 51, 51, 0.8);
color: #fff;
border-radius: 10px;
margin-bottom: 1%;
z-index: 2147483649;
transform: translateY(150px);
transition: .2s;
bottom: -50px;
/* 0 to show in preview */
}
.playerController * {
color: rgba(255, 255, 255, 0.9);
}
.playerController button {
background: none;
border: 0;
outline: 0;
text-align: center;
cursor: pointer;
}
.icon {
font-size: 16px;
font-family: 'Font Awesome 5 Free';
font-weight: 900;
}
.player:hover .playerController,
.player.paused .playerController {
transform: translateY(0);
}
.player__btn {
max-width: 50px;
}
.play::before {
content: '\f04b';
}
.pause::before {
content: '\f04c';
}
.progress {
/* position: relative; */
width: 50%;
cursor: pointer;
user-select: none;
height: 10px;
/* or 15px */
background: rgba(160, 154, 154, 0.8);
overflow: hidden;
border-radius: 50px;
}
.progressCurr {
height: 100%;
width: 0;
background: rgba(255, 255, 255, 0.9);
/* flex: 0;
flex-basis: 0%; */
/* old styles yellow progressCurr bg flex-basic insted of width*/
}
.fullscreen::before {
font-family: 'FontAwesome';
content: '\f065';
font-size: 16px
}
.player.isFullScreen .playerController .fullscreen::before {
content: '\f066';
}
.timeCurr,
.timeWhole {
font-size: 14px;
user-select: none;
}
.volumeContainer {
display: flex;
}
.volumeBC {
cursor: pointer;
padding-right: 5px;
}
.volumeRC {
width: 10px;
height: 30px;
}
.max::before {
content: '\f028'
}
.mute::before {
content: '\f6a9'
}
.bigPlayBtn {
font-size: 80px;
position: absolute;
top: 50%;
left: 50%;
cursor: pointer;
box-sizing: border-box;
transform: translate(-50%, -50%);
transition: .5s;
}
.bigPlayBtn::before {
content: '\f04b';
}
.HideBigPlayBtn {
cursor: default;
opacity: 0;
transform: translate(-50%, -50%) scale(1.2);
}
<div class='player paused CVP'>
<video class='video' src='http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4' width='700' height='350' poster='https://i.ytimg.com/vi/A1sVB8XBNDo/maxresdefault.jpg'>
</video>
<div class='bigPlayBtn icon'></div>
<div class='playerController'>
<button class='player__btn miniPlayBtn icon' title='Play/Pause'></button>
<div class='timeCurr'>00:00</div>
<div class='progress'>
<span id='buffered'>
<div class='progressCurr'></div>
</span>
</div>
<div class='timeWhole'>--:--</div>
<div class='volumeContainer'>
<button class='player__btn max volumeBC icon'></button>
<input type='range' name='volume' class='volume volumeRC' min='0' max='1' step='0.01' value='1' title='Volume' />
</div>
<button class='player__btn fullscreen icon' title='Full Screen'></button>
</div>
</div>
<div class='player paused CVP'>
<video class='video' src='http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4' width='700' height='350' poster='https://i.ytimg.com/vi/A1sVB8XBNDo/maxresdefault.jpg'>
</video>
<div class='bigPlayBtn icon'></div>
<div class='playerController'>
<button class='player__btn miniPlayBtn icon' title='Play/Pause'></button>
<div class='timeCurr'>00:00</div>
<div class='progress'>
<span id='buffered'>
<div class='progressCurr'></div>
</span>
</div>
<div class='timeWhole'>--:--</div>
<div class='volumeContainer'>
<button class='player__btn max volumeBC icon'></button>
<input type='range' name='volume' class='volume volumeRC' min='0' max='1' step='0.01' value='1' title='Volume' />
</div>
<button class='player__btn fullscreen icon' title='Full Screen'></button>
</div>
</div>
Sorry if I'm disturbing you for something that will probably appear you very simple, but I can't find a way to solve the problem on my own.
And, maybe, the title is not appropriated...
Well, I have a class with a constructor that works with HTML tag VIDEO, named CVP. It creates methods to act on video controls. The initial method consist in hooking the event listeners to HTML controls'classes.
Anyway, with a single VIDEO tag in the HTML code, it works correctly, but I don't know how to iterate the class on any VIDEO when there are many of them. This is an examples of the VIDEO tag:
<div class='player paused CVP'>
<video class='video' src="../../video/pietro.mp4">
</video>
etc...
This is the beginnig of the JS CLASS:
class CVP {
constructor (obj) {
const { P, V, PC, BPB, MPB, VRC, VBC, FS, PROG, PROGC, TW, TC } = obj;
this.player = document.querySelector(P);
this.video = document.querySelector(V);
etc..
The class ends this way:
(many other methods...)
init () {
// Hook up the Event Listeners
// toggle Play
this.video.addEventListener('click', this.togglePlay.bind(this));
this.miniPlayBtn.addEventListener('click', this.togglePlay.bind(this));
this.bigPlayBtn.addEventListener('click', this.togglePlay.bind(this));
etc...
}
}
Then, there's a inizialization's variable:
const initializeCVP = {
P: '.CVP',
V: '.video',
PC: '.playerController',
etc...
};
To add a single VIDEO tag:
const cvp = new CVP(initializeCVP);
cvp.init();
In this case it works perfectly. But, How can I assign the JS class to many VIDEO tags?
I tried this way, but it doesn't work:
window.onload = function () {
const CVPs = document.querySelectorAll('.CVP');
CVPs.forEach((cvp) => {
cvp = new CVP(initializeCVP);
cvp.init();
});
};
Is it clear? I hope so. I'm quite a beginner, so plase, don't complain...
Change your constructor so it takes elements rather than selectors. The caller can call document.querySelector() or document.querySelectorAll() when creating the initialization object.
class CVP {
constructor (obj) {
const { P, V, PC, BPB, MPB, VRC, VBC, FS, PROG, PROGC, TW, TC } = obj;
this.player = P;
this.video = V;
etc..
}
}
window.onload = function() {
const players = document.querySelectorAll('.player');
players.forEach(player => {
const initializeCVP = {
P: player,
V: player.querySelector('.video'),
PC: player.querySelector('.playerController'),
BPB: player.querySelector('.bigPlayBtn'),
MPB: player.querySelector('.miniPlayBtn'),
VRC: player.querySelector('.volumeRC'),
VBC: player.querySelector('.volumeBC'),
FS: player.querySelector('.fullscreen'),
PROG: player.querySelector('.progress'),
PROGC: player.querySelector('.progressCurr'),
TW: player.querySelector('.timeWhole'),
TC: player.querySelector('.timeCurr'),
};
const cvp = new CVP(initializeCVP);
cvp.init();
});
};
I found a way to fix what #Barman and #RandyCasburn pointed out regarding the single 'cvp' istance connected to class methods.
First, I applied #Barman suggestion, so to iterate all players has in the previous answer.
Then, I put a global array to collect the single 'cvp', with a couple of other new variables:
let cvpItems = [];
let cvpItem;
let currentCVP;
Then, I pushed all player istances in the HTML, applying to anyone an addEventListener. The window.onload code is changed in this way:
window.onload = function () {
const players = document.querySelectorAll('.player');
players.forEach(player => {
const initializeCVP = {
P: player,
V: player.querySelector('.video'),
PC: player.querySelector('.playerController'),
BPB: player.querySelector('.bigPlayBtn'),
MPB: player.querySelector('.miniPlayBtn'),
VRC: player.querySelector('.volumeRC'),
VBC: player.querySelector('.volumeBC'),
FS: player.querySelector('.fullscreen'),
PROG: player.querySelector('.progress'),
PROGC: player.querySelector('.progressCurr'),
TW: player.querySelector('.timeWhole'),
TC: player.querySelector('.timeCurr'),
};
cvpItem = new CVP(initializeCVP);
cvpItems.push(cvpItem);
cvpItem.init();
player.addEventListener('click', currentItem, false);
});
};
With the currentItem function I find the current player iteration using the title attribute in the HTML video tags:
let currentItem = function () {
for (var i = 0; i < cvpItems.length; i++) {
if (cvpItems[i].video.title == this.querySelectorAll('.video')[0].title) {
currentCVP = i;
break;
}
}
};
So, now I can identify the specific player in the JS class. For examples, the previous rangeVolumeController method changes from:
rangeVolumeController () {
cvp.video[this.name] = this.value;
if (cvp.volumeRangeController.value == 0) {
cvp.video.muted = true;
CVP.changeIcon(cvp.volumeBtnController, 'max', 'mute');
} else {
cvp.video.muted = false;
CVP.changeIcon(cvp.volumeBtnController, 'mute', 'max');
}
}
to
rangeVolumeController () {
console.log(CVP, this, event.target);
cvpItems[currentCVP].video[this.name] = this.value;
if (cvpItems[currentCVP].volumeRangeController.value == 0) {
cvpItems[currentCVP].video.muted = true;
CVP.changeIcon(cvpItems[currentCVP].volumeBtnController, 'max', 'mute');
} else {
cvpItems[currentCVP].video.muted = false;
CVP.changeIcon(cvpItems[currentCVP].volumeBtnController, 'mute', 'max');
}
}
It works! But, I know, it's not an elegant way for coding. If someone wants to propose a better or more "elegant" solution, I'll be grateful.
I've built a small balloon game , trying to learn the foundations,
anyways I've successfully rendered balloons, i can see them both on the page however the move functions doesn't work,it should do so on page load that I've set in the index.html body(the startGame func) , code looks fine,however nothing happens.
var gNextId = 100
var gBaloons = createBalloons()
var gInterval = null
function startGame() {
renderBaloons();
gInterval = setInterval(() => {
moveBalloons();
}, 500);
}
function renderBaloons() {
var strHtml = ''
for (var i = 0; i < gBaloons.length; i++) {
var balloon = gBaloons[i]
strHtml += `
${balloon.txt}
`
}
document.querySelector('.balloon-container').innerHTML = strHtml
}
function moveballoons() {
var elballoons = document.querySelectorAll('.balloon')
for (var i = 0; i > gBaloons.length; i++) {
var balloon = gBaloons[i]
var elballoon = elballoons[i]
balloon.bottom += balloon.speed
elballoon.style.bottom = balloon.bottom + 'px'
}
if (balloon.bottom >= 800) clearInterval(gInterval)
}
function createBalloons() {
var ballons = [
createBalloon('A'),
createBalloon('B'),
createBalloon('C')
];
return ballons
}
function createBalloon(txt) {
return {
id: gNextId++,
bottom: 0,
speed: 45,
txt: txt
}
}
body {
background-color: lightblue;
}
.balloon {
position: absolute;
width: 170px;
height: 200px;
border-radius: 40%;
bottom: 0;
transition: 3s;
background-color: yellow;
text-align: center;
font-weight: bold;
}
.balloon1 {
left: 200px;
background-color: rgb(3, 61, 23);
}
.balloon2 {
left: 600px;
background-color: rgb(182, 24, 50);
}
.fade {
opacity: 0;
}
In the moveballoons() function the following line:
for (var i = 0; i > gBaloons.length; i++) {
Should be
for (var i = 0; i < gBaloons.length; i++) {
Note: I've swapped > with <
I couldn't the get example running, so there could well be other reasons as to why this is not working but that is definitely an issue.
I want to apply magnifying glass and lightbox both on an image so when a user hovers on an image the glass effect will appear and when he clicks the lightbox will appear. But in my case the lightbox stopped working when I actived the magnifying glass. So when I remove the glass CSS lightbox worked normally.
/*!
* Lightbox v2.10.0
* by Lokesh Dhakar
*
* More info:
* http://lokeshdhakar.com/projects/lightbox2/
*
* Copyright 2007, 2018 Lokesh Dhakar
* Released under the MIT license
* https://github.com/lokesh/lightbox2/blob/master/LICENSE
*
* #preserve
*/
! function(a, b) {
"function" == typeof define && define.amd ? define(["jquery"], b) : "object" == typeof exports ? module.exports = b(require("jquery")) : a.lightbox = b(a.jQuery)
}(this, function(a) {
function b(b) {
this.album = [], this.currentImageIndex = void 0, this.init(), this.options = a.extend({}, this.constructor.defaults), this.option(b)
}
return b.defaults = {
albumLabel: "Image %1 of %2",
alwaysShowNavOnTouchDevices: !1,
fadeDuration: 600,
fitImagesInViewport: !0,
imageFadeDuration: 600,
positionFromTop: 50,
resizeDuration: 700,
showImageNumberLabel: !0,
wrapAround: !1,
disableScrolling: !1,
sanitizeTitle: !1
}, b.prototype.option = function(b) {
a.extend(this.options, b)
}, b.prototype.imageCountLabel = function(a, b) {
return this.options.albumLabel.replace(/%1/g, a).replace(/%2/g, b)
}, b.prototype.init = function() {
var b = this;
a(document).ready(function() {
b.enable(), b.build()
})
}, b.prototype.enable = function() {
var b = this;
a("body").on("click", "a[rel^=lightbox], area[rel^=lightbox], a[data-lightbox], area[data-lightbox]", function(c) {
return b.start(a(c.currentTarget)), !1
})
}, b.prototype.build = function() {
if (!(a("#lightbox").length > 0)) {
var b = this;
a('<div id="lightboxOverlay" class="lightboxOverlay"></div><div id="lightbox" class="lightbox"><div class="lb-outerContainer"><div class="lb-container"><img class="lb-image" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" /><div class="lb-nav"><a class="lb-prev" href="" ></a><a class="lb-next" href="" ></a></div><div class="lb-loader"><a class="lb-cancel"></a></div></div></div><div class="lb-dataContainer"><div class="lb-data"><div class="lb-details"><span class="lb-caption"></span><span class="lb-number"></span></div><div class="lb-closeContainer"><a class="lb-close"></a></div></div></div></div>').appendTo(a("body")), this.$lightbox = a("#lightbox"), this.$overlay = a("#lightboxOverlay"), this.$outerContainer = this.$lightbox.find(".lb-outerContainer"), this.$container = this.$lightbox.find(".lb-container"), this.$image = this.$lightbox.find(".lb-image"), this.$nav = this.$lightbox.find(".lb-nav"), this.containerPadding = {
top: parseInt(this.$container.css("padding-top"), 10),
right: parseInt(this.$container.css("padding-right"), 10),
bottom: parseInt(this.$container.css("padding-bottom"), 10),
left: parseInt(this.$container.css("padding-left"), 10)
}, this.imageBorderWidth = {
top: parseInt(this.$image.css("border-top-width"), 10),
right: parseInt(this.$image.css("border-right-width"), 10),
bottom: parseInt(this.$image.css("border-bottom-width"), 10),
left: parseInt(this.$image.css("border-left-width"), 10)
}, this.$overlay.hide().on("click", function() {
return b.end(), !1
}), this.$lightbox.hide().on("click", function(c) {
return "lightbox" === a(c.target).attr("id") && b.end(), !1
}), this.$outerContainer.on("click", function(c) {
return "lightbox" === a(c.target).attr("id") && b.end(), !1
}), this.$lightbox.find(".lb-prev").on("click", function() {
return 0 === b.currentImageIndex ? b.changeImage(b.album.length - 1) : b.changeImage(b.currentImageIndex - 1), !1
}), this.$lightbox.find(".lb-next").on("click", function() {
return b.currentImageIndex === b.album.length - 1 ? b.changeImage(0) : b.changeImage(b.currentImageIndex + 1), !1
}), this.$nav.on("mousedown", function(a) {
3 === a.which && (b.$nav.css("pointer-events", "none"), b.$lightbox.one("contextmenu", function() {
setTimeout(function() {
this.$nav.css("pointer-events", "auto")
}.bind(b), 0)
}))
}), this.$lightbox.find(".lb-loader, .lb-close").on("click", function() {
return b.end(), !1
})
}
}, b.prototype.start = function(b) {
function c(a) {
d.album.push({
alt: a.attr("data-alt"),
link: a.attr("href"),
title: a.attr("data-title") || a.attr("title")
})
}
var d = this,
e = a(window);
e.on("resize", a.proxy(this.sizeOverlay, this)), a("select, object, embed").css({
visibility: "hidden"
}), this.sizeOverlay(), this.album = [];
var f, g = 0,
h = b.attr("data-lightbox");
if (h) {
f = a(b.prop("tagName") + '[data-lightbox="' + h + '"]');
for (var i = 0; i < f.length; i = ++i) c(a(f[i])), f[i] === b[0] && (g = i)
} else if ("lightbox" === b.attr("rel")) c(b);
else {
f = a(b.prop("tagName") + '[rel="' + b.attr("rel") + '"]');
for (var j = 0; j < f.length; j = ++j) c(a(f[j])), f[j] === b[0] && (g = j)
}
var k = e.scrollTop() + this.options.positionFromTop,
l = e.scrollLeft();
this.$lightbox.css({
top: k + "px",
left: l + "px"
}).fadeIn(this.options.fadeDuration), this.options.disableScrolling && a("html").addClass("lb-disable-scrolling"), this.changeImage(g)
}, b.prototype.changeImage = function(b) {
var c = this;
this.disableKeyboardNav();
var d = this.$lightbox.find(".lb-image");
this.$overlay.fadeIn(this.options.fadeDuration), a(".lb-loader").fadeIn("slow"), this.$lightbox.find(".lb-image, .lb-nav, .lb-prev, .lb-next, .lb-dataContainer, .lb-numbers, .lb-caption").hide(), this.$outerContainer.addClass("animating");
var e = new Image;
e.onload = function() {
var f, g, h, i, j, k;
d.attr({
alt: c.album[b].alt,
src: c.album[b].link
}), a(e), d.width(e.width), d.height(e.height), c.options.fitImagesInViewport && (k = a(window).width(), j = a(window).height(), i = k - c.containerPadding.left - c.containerPadding.right - c.imageBorderWidth.left - c.imageBorderWidth.right - 20, h = j - c.containerPadding.top - c.containerPadding.bottom - c.imageBorderWidth.top - c.imageBorderWidth.bottom - 120, c.options.maxWidth && c.options.maxWidth < i && (i = c.options.maxWidth), c.options.maxHeight && c.options.maxHeight < i && (h = c.options.maxHeight), (e.width > i || e.height > h) && (e.width / i > e.height / h ? (g = i, f = parseInt(e.height / (e.width / g), 10), d.width(g), d.height(f)) : (f = h, g = parseInt(e.width / (e.height / f), 10), d.width(g), d.height(f)))), c.sizeContainer(d.width(), d.height())
}, e.src = this.album[b].link, this.currentImageIndex = b
}, b.prototype.sizeOverlay = function() {
this.$overlay.width(a(document).width()).height(a(document).height())
}, b.prototype.sizeContainer = function(a, b) {
function c() {
d.$lightbox.find(".lb-dataContainer").width(g), d.$lightbox.find(".lb-prevLink").height(h), d.$lightbox.find(".lb-nextLink").height(h), d.showImage()
}
var d = this,
e = this.$outerContainer.outerWidth(),
f = this.$outerContainer.outerHeight(),
g = a + this.containerPadding.left + this.containerPadding.right + this.imageBorderWidth.left + this.imageBorderWidth.right,
h = b + this.containerPadding.top + this.containerPadding.bottom + this.imageBorderWidth.top + this.imageBorderWidth.bottom;
e !== g || f !== h ? this.$outerContainer.animate({
width: g,
height: h
}, this.options.resizeDuration, "swing", function() {
c()
}) : c()
}, b.prototype.showImage = function() {
this.$lightbox.find(".lb-loader").stop(!0).hide(), this.$lightbox.find(".lb-image").fadeIn(this.options.imageFadeDuration), this.updateNav(), this.updateDetails(), this.preloadNeighboringImages(), this.enableKeyboardNav()
}, b.prototype.updateNav = function() {
var a = !1;
try {
document.createEvent("TouchEvent"), a = !!this.options.alwaysShowNavOnTouchDevices
} catch (a) {}
this.$lightbox.find(".lb-nav").show(), this.album.length > 1 && (this.options.wrapAround ? (a && this.$lightbox.find(".lb-prev, .lb-next").css("opacity", "1"), this.$lightbox.find(".lb-prev, .lb-next").show()) : (this.currentImageIndex > 0 && (this.$lightbox.find(".lb-prev").show(), a && this.$lightbox.find(".lb-prev").css("opacity", "1")), this.currentImageIndex < this.album.length - 1 && (this.$lightbox.find(".lb-next").show(), a && this.$lightbox.find(".lb-next").css("opacity", "1"))))
}, b.prototype.updateDetails = function() {
var b = this;
if (void 0 !== this.album[this.currentImageIndex].title && "" !== this.album[this.currentImageIndex].title) {
var c = this.$lightbox.find(".lb-caption");
this.options.sanitizeTitle ? c.text(this.album[this.currentImageIndex].title) : c.html(this.album[this.currentImageIndex].title), c.fadeIn("fast").find("a").on("click", function(b) {
void 0 !== a(this).attr("target") ? window.open(a(this).attr("href"), a(this).attr("target")) : location.href = a(this).attr("href")
})
}
if (this.album.length > 1 && this.options.showImageNumberLabel) {
var d = this.imageCountLabel(this.currentImageIndex + 1, this.album.length);
this.$lightbox.find(".lb-number").text(d).fadeIn("fast")
} else this.$lightbox.find(".lb-number").hide();
this.$outerContainer.removeClass("animating"), this.$lightbox.find(".lb-dataContainer").fadeIn(this.options.resizeDuration, function() {
return b.sizeOverlay()
})
}, b.prototype.preloadNeighboringImages = function() {
if (this.album.length > this.currentImageIndex + 1) {
(new Image).src = this.album[this.currentImageIndex + 1].link
}
if (this.currentImageIndex > 0) {
(new Image).src = this.album[this.currentImageIndex - 1].link
}
}, b.prototype.enableKeyboardNav = function() {
a(document).on("keyup.keyboard", a.proxy(this.keyboardAction, this))
}, b.prototype.disableKeyboardNav = function() {
a(document).off(".keyboard")
}, b.prototype.keyboardAction = function(a) {
var b = a.keyCode,
c = String.fromCharCode(b).toLowerCase();
27 === b || c.match(/x|o|c/) ? this.end() : "p" === c || 37 === b ? 0 !== this.currentImageIndex ? this.changeImage(this.currentImageIndex - 1) : this.options.wrapAround && this.album.length > 1 && this.changeImage(this.album.length - 1) : "n" !== c && 39 !== b || (this.currentImageIndex !== this.album.length - 1 ? this.changeImage(this.currentImageIndex + 1) : this.options.wrapAround && this.album.length > 1 && this.changeImage(0))
}, b.prototype.end = function() {
this.disableKeyboardNav(), a(window).off("resize", this.sizeOverlay), this.$lightbox.fadeOut(this.options.fadeDuration), this.$overlay.fadeOut(this.options.fadeDuration), a("select, object, embed").css({
visibility: "visible"
}), this.options.disableScrolling && a("html").removeClass("lb-disable-scrolling")
}, new b
});
//# sourceMappingURL=lightbox.min.map
//magnyfing glass
$(function() {
var native_width = 0;
var native_height = 0;
var mouse = {
x: 0,
y: 0
};
var magnify;
var cur_img;
var ui = {
magniflier: $('.magniflier')
};
// Add the magnifying glass
if (ui.magniflier.length) {
var div = document.createElement('div');
div.setAttribute('class', 'glass');
ui.glass = $(div);
$('body').append(div);
}
// All the magnifying will happen on "mousemove"
var mouseMove = function(e) {
var $el = $(this);
// Container offset relative to document
var magnify_offset = cur_img.offset();
// Mouse position relative to container
// pageX/pageY - container's offsetLeft/offetTop
mouse.x = e.pageX - magnify_offset.left;
mouse.y = e.pageY - magnify_offset.top;
// The Magnifying glass should only show up when the mouse is inside
// It is important to note that attaching mouseout and then hiding
// the glass wont work cuz mouse will never be out due to the glass
// being inside the parent and having a higher z-index (positioned above)
if (
mouse.x < cur_img.width() &&
mouse.y < cur_img.height() &&
mouse.x > 0 &&
mouse.y > 0
) {
magnify(e);
} else {
ui.glass.fadeOut(100);
}
return;
};
var magnify = function(e) {
// The background position of div.glass will be
// changed according to the position
// of the mouse over the img.magniflier
//
// So we will get the ratio of the pixel
// under the mouse with respect
// to the image and use that to position the
// large image inside the magnifying glass
var rx = Math.round(mouse.x / cur_img.width() * native_width - ui.glass.width() / 2) * -1;
var ry = Math.round(mouse.y / cur_img.height() * native_height - ui.glass.height() / 2) * -1;
var bg_pos = rx + "px " + ry + "px";
// Calculate pos for magnifying glass
//
// Easy Logic: Deduct half of width/height
// from mouse pos.
// var glass_left = mouse.x - ui.glass.width() / 2;
// var glass_top = mouse.y - ui.glass.height() / 2;
var glass_left = e.pageX - ui.glass.width() / 2;
var glass_top = e.pageY - ui.glass.height() / 2;
//console.log(glass_left, glass_top, bg_pos)
// Now, if you hover on the image, you should
// see the magnifying glass in action
ui.glass.css({
left: glass_left,
top: glass_top,
backgroundPosition: bg_pos
});
return;
};
$('.magniflier').on('mousemove', function() {
ui.glass.fadeIn(200);
cur_img = $(this);
var large_img_loaded = cur_img.data('large-img-loaded');
var src = cur_img.data('large') || cur_img.attr('src');
// Set large-img-loaded to true
// cur_img.data('large-img-loaded', true)
if (src) {
ui.glass.css({
'background-image': 'url(' + src + ')',
'background-repeat': 'no-repeat'
});
}
// When the user hovers on the image, the script will first calculate
// the native dimensions if they don't exist. Only after the native dimensions
// are available, the script will show the zoomed version.
//if(!native_width && !native_height) {
if (!cur_img.data('native_width')) {
// This will create a new image object with the same image as that in .small
// We cannot directly get the dimensions from .small because of the
// width specified to 200px in the html. To get the actual dimensions we have
// created this image object.
var image_object = new Image();
image_object.onload = function() {
// This code is wrapped in the .load function which is important.
// width and height of the object would return 0 if accessed before
// the image gets loaded.
native_width = image_object.width;
native_height = image_object.height;
cur_img.data('native_width', native_width);
cur_img.data('native_height', native_height);
//console.log(native_width, native_height);
mouseMove.apply(this, arguments);
ui.glass.on('mousemove', mouseMove);
};
image_object.src = src;
return;
} else {
native_width = cur_img.data('native_width');
native_height = cur_img.data('native_height');
}
//}
//console.log(native_width, native_height);
mouseMove.apply(this, arguments);
ui.glass.on('mousemove', mouseMove);
});
ui.glass.on('mouseout', function() {
ui.glass.off('mousemove', mouseMove);
});
});
html.lb-disable-scrolling {
overflow: hidden;
/* Position fixed required for iOS. Just putting overflow: hidden; on the body is not enough. */
position: fixed;
height: 100vh;
width: 100vw;
}
.lightboxOverlay {
position: absolute;
top: 0;
left: 0;
z-index: 9999;
background-color: black;
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
opacity: 0.8;
display: none;
}
.lightbox {
position: absolute;
left: 0;
width: 100%;
z-index: 10000;
text-align: center;
line-height: 0;
font-weight: normal;
}
.lightbox .lb-image {
display: block;
height: auto;
max-width: inherit;
max-height: none;
border-radius: 3px;
/* Image border */
border: 4px solid white;
}
.lightbox a img {
border: none;
}
.lb-outerContainer {
position: relative;
*zoom: 1;
width: 250px;
height: 250px;
margin: 0 auto;
border-radius: 4px;
/* Background color behind image.
This is visible during transitions. */
background-color: white;
}
.lb-outerContainer:after {
content: "";
display: table;
clear: both;
}
.lb-loader {
position: absolute;
top: 43%;
left: 0;
height: 25%;
width: 100%;
text-align: center;
line-height: 0;
}
.lb-cancel {
display: block;
width: 32px;
height: 32px;
margin: 0 auto;
background: url(../assets/imgs/lightbox/loading.gif) no-repeat;
}
.lb-nav {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
z-index: 10;
}
.lb-container>.nav {
left: 0;
}
.lb-nav a {
outline: none;
background-image: url('data:image/gif;base64,R0lGODlhAQABAPAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==');
}
.lb-prev,
.lb-next {
height: 100%;
cursor: pointer;
display: block;
}
.lb-nav a.lb-prev {
width: 34%;
left: 0;
float: left;
background: url(../assets/imgs/lightbox/prev.png) left 48% no-repeat;
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0);
opacity: 0;
-webkit-transition: opacity 0.6s;
-moz-transition: opacity 0.6s;
-o-transition: opacity 0.6s;
transition: opacity 0.6s;
}
.lb-nav a.lb-prev:hover {
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
opacity: 1;
}
.lb-nav a.lb-next {
width: 64%;
right: 0;
float: right;
background: url(../assets/imgs/lightbox/next.png) right 48% no-repeat;
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0);
opacity: 0;
-webkit-transition: opacity 0.6s;
-moz-transition: opacity 0.6s;
-o-transition: opacity 0.6s;
transition: opacity 0.6s;
}
.lb-nav a.lb-next:hover {
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
opacity: 1;
}
.lb-dataContainer {
margin: 0 auto;
padding-top: 5px;
*zoom: 1;
width: 100%;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
.lb-dataContainer:after {
content: "";
display: table;
clear: both;
}
.lb-data {
padding: 0 4px;
color: #ccc;
}
.lb-data .lb-details {
width: 85%;
float: left;
text-align: left;
line-height: 1.1em;
}
.lb-data .lb-caption {
font-size: 13px;
font-weight: bold;
line-height: 1em;
}
.lb-data .lb-caption a {
color: #4ae;
}
.lb-data .lb-number {
display: block;
clear: left;
padding-bottom: 1em;
font-size: 12px;
color: #999999;
}
.lb-data .lb-close {
display: block;
float: right;
width: 30px;
height: 30px;
background: url(../assets/imgs/lightbox/close.png) top right no-repeat;
text-align: right;
outline: none;
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=70);
opacity: 0.7;
-webkit-transition: opacity 0.2s;
-moz-transition: opacity 0.2s;
-o-transition: opacity 0.2s;
transition: opacity 0.2s;
}
.lb-data .lb-close:hover {
cursor: pointer;
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
opacity: 1;
}
/* IF you remove this, lightbox will work but not the magnyfing glass */
.glass {
width: 150px;
height: 150px;
position: absolute;
border-radius: 50%;
cursor: crosshair;
/* Multiple box shadows to achieve the glass effect */
box-shadow: 0 0 0 7px rgba(255, 255, 255, 0.85), 0 0 7px 7px rgba(0, 0, 0, 0.25), inset 0 0 40px 2px rgba(0, 0, 0, 0.25);
/* hide the glass by default */
display: none;
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!--START BOOK PREVIEW-->
<div class="book-preview px-5 py-5 container img-magnifier-container">
<div class="row">
<div class="col-lg-4 book">
<a href="https://subsolardesigns.com/odrin/demo1/wp-content/uploads/sites/8/2017/08/cover_taurus-468x700.png" data-lightbox="image-1" data-title="My caption">
<img src="https://subsolardesigns.com/odrin/demo1/wp-content/uploads/sites/8/2017/08/cover_taurus-468x700.png" alt="Book" class="img-fluid magniflier" id="book-glass" alt="Responsive image">
</a>
</div>
</div>
</div>
The issue is that you are not clicking the image, but the .glass dom node. You need to handle the click event on the .glass element and then call click on the image, in order for the lightbox plugin to do what it expects to do. Add the code below to you javascript to redirect the click event to your image tag.
ui.glass.on('click', function() {
cur_img.click();
});
Title says it all really. Here is an example of what I'm trying to achieve navigation color change image based on background
The problem is that it needs to work with a site that's using a scroll-jacking parallax type effect, here is the site I'm trying to achieve this effect with demo website
Modify the scroll script a bit
Check demo here
Created the function toggleHeaderColor to check the current section. Since the scroll script is indexing each section in order 0 (i.e. section_1) ,1 (i.e. section_2),2 (i.e. section_2),3 (i.e. section_3),4 (i.e. section_2) and so on. Every time you scroll it gets updated.
In scroll script there are two function nextItem() and previousItem()form which we get the current slide index and on that we can call our function to toggle dark class on header elements.
JS:
var sectionBlock = $(".section-item");
var getCurrentSlideAttr = 0;
function toggleHeaderColor(getCurrentSlideAttr) {
if (getCurrentSlideAttr == 0) {
$(".menu-link, .menu-link-logo, .menu-link-last").removeClass("dark");
}
if (getCurrentSlideAttr == 1) {
$(".menu-link, .menu-link-logo, .menu-link-last").addClass("dark");
}
if (getCurrentSlideAttr == 2) {
$(".menu-link, .menu-link-logo, .menu-link-last").removeClass("dark");
}
if (getCurrentSlideAttr == 3) {
$(".menu-link, .menu-link-logo, .menu-link-last").removeClass("dark");
}
if (getCurrentSlideAttr == 4) {
$(".menu-link, .menu-link-logo, .menu-link-last").addClass("dark");
}
}
var ticking = false;
var isFirefox = /Firefox/i.test(navigator.userAgent);
var isIe =
/MSIE/i.test(navigator.userAgent) ||
/Trident.*rv\:11\./i.test(navigator.userAgent);
var scrollSensitivitySetting = 30;
var slideDurationSetting = 800;
var currentSlideNumber = 0;
var totalSlideNumber = $(".section-item").length;
function parallaxScroll(evt) {
if (isFirefox) {
delta = evt.detail * -120;
} else if (isIe) {
delta = -evt.deltaY;
} else {
delta = evt.wheelDelta;
}
if (ticking != true) {
if (delta <= -scrollSensitivitySetting) {
ticking = true;
if (currentSlideNumber !== totalSlideNumber - 1) {
currentSlideNumber++;
nextItem();
}
slideDurationTimeout(slideDurationSetting);
}
if (delta >= scrollSensitivitySetting) {
ticking = true;
if (currentSlideNumber !== 0) {
currentSlideNumber--;
}
previousItem();
slideDurationTimeout(slideDurationSetting);
}
}
}
function slideDurationTimeout(slideDuration) {
setTimeout(function() {
ticking = false;
}, slideDuration);
}
var mousewheelEvent = isFirefox ? "DOMMouseScroll" : "wheel";
window.addEventListener(mousewheelEvent, _.throttle(parallaxScroll, 60), false);
function nextItem() {
getCurrentSlideAttr = currentSlideNumber;
toggleHeaderColor(getCurrentSlideAttr);
var $previousSlide = $(".section-item").eq(currentSlideNumber - 1);
$previousSlide
.css("transform", "translate3d(0,-130vh,0)")
.find(".content-wrapper")
.css("transform", "translateY(40vh)");
currentSlideTransition();
}
function previousItem() {
//console.log($(".section-item").eq(currentSlideNumber).attr('id'))
getCurrentSlideAttr = currentSlideNumber;
toggleHeaderColor(getCurrentSlideAttr);
var $previousSlide = $(".section-item").eq(currentSlideNumber + 1);
$previousSlide
.css("transform", "translate3d(0,30vh,0)")
.find(".content-wrapper")
.css("transform", "translateY(30vh)");
currentSlideTransition();
}
function currentSlideTransition() {
var $currentSlide = $(".section-item").eq(currentSlideNumber);
$currentSlide
.css("transform", "translate3d(0,-15vh,0)")
.find(".content-wrapper")
.css("transform", "translateY(15vh)");
}
Update
You can actually choose a specific text color over white/black backgrounds using css blend modes.
Example with specific colors (green over white and red over black in this case):
html, body {
margin: 0;
}
h1 {
position: fixed; top: 0; left: 0;
width: 100vw;
text-align: center;
mix-blend-mode: difference;
color: white;
z-index: 1;
}
div {
position: relative;
width: 100vw;
height: 100vh;
background: white;
margin: 0;
}
div:nth-of-type(2n) {
background: black;
}
div:after {
content: '';
position: absolute; top: 0; left: 0;
width: 100%;
height: 100%;
z-index: 2;
}
div:nth-of-type(2n):after {
background: red;
mix-blend-mode: multiply;
}
div:nth-of-type(2n + 1):after {
background: green;
mix-blend-mode: screen;
}
<h1>Scroll to see effect</h1>
<div></div>
<div></div>
<div></div>
I think the only way you would be able to choose the exact partial colors using SVG text or paths.
A simple example with mix-blend-mode:
html, body {
margin: 0;
}
h1 {
position: fixed; top: 0; left: 0;
width: 100vw;
text-align: center;
mix-blend-mode: difference;
color: white;
z-index: 1;
}
div {
width: 100vw;
height: 100vh;
background: black;
}
div:nth-of-type(2n) {
background: white;
}
<h1>Scroll to see effect</h1>
<div></div>
<div></div>
<div></div>
Browser support
https://css-tricks.com/reverse-text-color-mix-blend-mode/
Try Adding mix-blend-mode property.
Add this property to your .navigation-menu class
CSS
.navigation-menu{
mix-blend-mode: difference;
}
Hope this Helps...
Please I need I help on how to implement something like this responsively using bootstrap
html code for is displayed below
<div class="wrapper">
<div class="container">
<div class="special">
<div id="counter">
<div id="shading"></div>
</div>
</div>
</div>
please below is the css file for the above html code
.special
{
position: relative;
width: 840px;
height: 247px;
background-image: url('https://www.jqueryscript.net/demo/Colorful-Countdown-Timer/images/special_offer_bg.png');
background-position: -10px 74px;
background-repeat: no-repeat;
}
#counter
{
position: absolute;
top: 135px;
left: 279px;
z-index: 4000;
}
.digit-separator
{
position: relative;
float: left;
width: 17px;
height: 44px;
overflow: hidden;
background-image: url('https://www.jqueryscript.net/demo/Colorful-Countdown-Timer/images/digit_separator.png');
background-repeat: no-repeat;
background-position: 0px 0px;
}
.digit
{
background-image: url('https://www.jqueryscript.net/demo/Colorful-Countdown-Timer/images/digits.png');
}
#shading
{
background-image: url('https://www.jqueryscript.net/demo/Colorful-Countdown-Timer/images/sprites.png');
background-position: 0px -396px;
background-repeat: repeat-x;
float: left;
height: 44px;
position: absolute;
width: 291px;
z-index: 4100;
top: 0;
left: 0;
}
please this is the JavaScript code for the above html code
function C3Counter(id, opt) {
this.options = {
stepTime: 60, // not used
format: "dd:hh:mm:ss", // not used
startTime: "01:04:40:59",
digitImages: 1,
digitWidth: 30,
digitHeight: 44,
digitSlide : true,
digitSlideTime : 200,
digitImageHeight : 484,
digitAnimationHeight : 44,
timerEnd: function(){},
image: "digits.png",
updateInterval : 1000
};
var s;
if (typeof opt != "undefined") {
for (s in this.options) {
if (typeof opt[s] != "undefined") {
this.options[s] = opt[s];
}
}
}
if (String(options.startTime).indexOf(":") == -1) {
options.tempStartTime = options.startTime;
} else {
//TODO - does not convert time with : to seconds to count
var td = new Date(options.startTime);
}
this.pad2 = function(number) {
return (number < 10 ? '0' : '') + number;
}
var timer = setInterval( "this.updateCounter()", options.updateInterval);
var startTime = new Date().getTime();
var secNo = 0;
var timerSingle = new Array();
var dc = 0;
var digits = new Array();
var d = new Date();
var lastTime = d.getTime();
this.calculateTime = function() {
var tempTime = options.tempStartTime;
if (String(options.tempStartTime).indexOf(":") == -1) {
var seconds=Math.round(options.tempStartTime % 60);
options.tempStartTime=Math.floor(options.tempStartTime/60);
var minutes=Math.round(options.tempStartTime % 60);
options.tempStartTime=Math.floor(options.tempStartTime/60);
var hours=Math.round(options.tempStartTime % 24);
options.tempStartTime=Math.floor(options.tempStartTime/24);
var days=Math.round(options.tempStartTime);
options.timeStr = this.pad2(days)+this.pad2(hours)+this.pad2(minutes)+this.pad2(seconds);
}
var currTime = new Date().getTime();
var diff = currTime - startTime;
options.tempStartTime = options.startTime - Math.round(diff/1000);
}
this.calculateTime();
for (dc=0; dc<8; dc++) {
digits[dc] = { digit: this.options.timeStr.charAt(dc)};
$("#"+id).append("<div id='digit"+dc+"' style='position:relative;float:left;width:"+this.options.digitWidth+"px;height:"+this.options.digitHeight+"px;overflow:hidden;'><div class='digit' id='digit-bg"+dc+"' style='position:absolute; top:-"+digits[dc].digit*this.options.digitAnimationHeight+"px; width:"+this.options.digitWidth+"px; height:"+this.options.digitImageHeight+"px; '></div></div>");
if (dc % 2 == 1 && dc < 6) {
$("#"+id).append("<div class='digit-separator' style='float:left;'></div>");
}
}
$("#"+id).append("<div style='clear:both'></div>");
this.animateDigits = function() {
for (var dc=0; dc<8; dc++) {
digits[dc].digitNext = Number(this.options.timeStr.charAt(dc));
digits[dc].digitNext = (digits[dc].digitNext + 10)%10;
var no = dc;
if (digits[no].digit == 0) $("#digit-bg"+no).css("top", -this.options.digitImageHeight+this.options.digitHeight + "px");
if (digits[no].digit != digits[no].digitNext) {
$("#digit-bg"+no).animate( { "top" : -digits[no].digitNext*options.digitHeight+"px"}, options.digitSlideTime);
digits[no].digit = digits[no].digitNext;
}
}
var end = this.checkEnd();
}
this.checkEnd = function() {
for (var i = 0; i < digits.length; i++) {
if (digits[i].digit != 0) {
return false;
}
}
clearInterval(timer);
this.options.timerEnd();
return true;
}
this.updateCounter = function() {
d = new Date();
if ((d.getTime() - lastTime) < (options.updateInterval - 50)) {
return;
}
lastTime = d.getTime();
this.calculateTime();
this.animateDigits();
}
}
C3Counter("counter", { startTime :16100 });
Note* you need to use Bootstrap v3.3.4 or higher and jQuery v2.1.3 or higher
Note* This doesnt look like the exact example you linked to. Its not posible to achieve that with default boostrap library.
html:
<div class="wrapper">
<div class="special">
<span id="clock"></span>
</div>
</div>
js:
$('#clock').countdown('2020/10/10', function(event) {
$(this).html(event.strftime('%D days %H:%M:%S'));
});
css:
.wrapper
{
width: 100%;
height: auto;
background-color: #dc403b;
}
.special
{
width:100%;
background-image: url('https://www.jqueryscript.net/demo/Colorful-Countdown-Timer/images/special_offer_bg.png');
background-position: cover;
background-repeat: no-repeat;
text-align: center;
padding: 50px 0;
font-size: 18px;
}