In building a custom carousel with Hammer JS 2.0.8, I had some trouble making it work fluidly. After multiple tries, I found a snippet that really helped, and when I eventually completed the module, I decided to equally share here
This was the snippet that really helped from Richard Liu.
For some reason, switching back to Hammer 2.0.4 made the pancancel/panend callbacks more reliable. From there, I was able to complete my solution. A complete demo is also on JSFiddle
class Carousel {
constructor(options) {
this.transiting = false;
this.activeCard = 1;
this.offset = 0;
this.delta = 0;
this.element = options.carousel;
this.slides = this.element.children.length;
this.element.style.width = `${this.slides * 100}%`;
this.width = options.carousel.clientWidth;
this.boundaryLeft = 0;
this.boundaryRight = ((this.count - 1) / this.count) * this.width;
this.outOfBounds = false;
this.panRequiredToMove = options.container.clientWidth * 0.25;
this.hammer = new Hammer(options.container);
this.init();
}
init() {
var self = this;
function handleHammer(e) {
switch (e.type) {
case 'swipeleft':
case 'swiperight':
self.handleSwipe(e);
break;
case 'panleft':
case 'panright':
case 'panend':
case 'pancancel':
self.handlePan(e);
break;
}
}
this.hammer.on('swipeleft swiperight panleft panright panend pancancel', handleHammer);
this.element.addEventListener("transitionend", function (event) {
this.classList.remove('carousel--in-motion');
}, false);
}
handleSwipe(e) {
switch (e.direction) {
case Hammer.DIRECTION_LEFT:
this.next();
break;
case Hammer.DIRECTION_RIGHT:
this.previous();
break;
}
this.hammer.stop(true);
}
checkBounds() {
var beforeFirstCard = this.activeCard === 1 && (this.offset + this.delta) >= this.boundaryLeft;
var afterLastCard = this.activeCard === this.slides && Math.abs(this.offset + this.delta) >= this.boundaryRight;
if (beforeFirstCard) {
this.outOfBounds = { recoilPosition: this.boundaryLeft };
} else if (afterLastCard) {
this.outOfBounds = { recoilPosition: this.boundaryRight * -1 };
} else {
this.outOfBounds = false;
}
}
handlePan(e) {
switch (e.type) {
case 'panleft':
case 'panright':
this.checkBounds();
if (this.outOfBounds) e.deltaX *= .2;
this.transition(e.deltaX);
break;
case 'panend':
case 'pancancel':
if (this.outOfBounds) {
this.recoil(this.outOfBounds.recoilPosition);
} else if (Math.abs(e.deltaX) > this.panRequiredToMove) {
e.deltaX > 0 ? this.previous() : this.next();
} else {
this.recoil();
}
break;
}
}
next() {
if (this.activeCard < this.slides) {
let newPosition = this.activeCard / this.slides * this.width * -1;
this.goToSlide(newPosition, () => {
this.activeCard++;
});
}
}
previous() {
if (this.activeCard > 1) {
let activeCard = this.activeCard - (this.slides - 1);
let newPosition = activeCard / this.slides * this.width * -1;
this.goToSlide(newPosition, () => {
this.activeCard--;
});
}
}
goToSlide(position, callback) {
let self = this;
let currentPosition = this.offset + this.delta;
this.transiting = true;
// I used AnimatePlus for the other movement between slides
animate({
el: this.element,
translateX: [`${currentPosition}px`, `${position}px`],
duration: 300,
easing: "easeInOutQuad",
complete() {
self.transiting = false;
self.offset = position;
self.delta = 0;
if (callback) callback();
}
});
}
transition(deltaX) {
this.delta = deltaX;
let position = this.offset + this.delta;
this.element.style.webkitTransform = `translateX(${position}px)`;
}
recoil(position) {
this.element.classList.add('carousel--in-motion');
this.element.style.webkitTransform = `translateX(${position || this.offset}px)`;
}
}
Related
Some time ago I wrote some code to modify an image size in a modern UI WinJS application using the WinRT API.
Now I'm being asked to also change the image resolution to 2.7 times its biggest side (don't ask).
Problem is I can't find the proper way - if it exists - to set the resolution of an image using WinRT.
Here is the code so far. Note that it takes into account multiple frames images (like GIFs).
function resizePictureAsync(file) {
const MAX_HEIGHT = 1600,
MAX_WIDTH = 1600,
RATIO_FOR_TWO_COLUMN_WORD_FIT = 2.7;
var inStream = null, outStream = null;
return file.openAsync(Windows.Storage.FileAccessMode.read).then(function (stream) {
inStream = stream;
return Windows.Graphics.Imaging.BitmapDecoder.createAsync(stream);
}).then(function (decoder) {
return Windows.Storage.ApplicationData.current.temporaryFolder.createFileAsync("temp-picture-resize", Windows.Storage.CreationCollisionOption.replaceExisting).then(function (resizedFile) {
return resizedFile.openAsync(Windows.Storage.FileAccessMode.readWrite).then(function (stream) {
outStream = stream;
return Windows.Graphics.Imaging.BitmapEncoder.createForTranscodingAsync(outStream, decoder);
}).then(function (encoder) {
var framesMasterPromise = WinJS.Promise.wrap(null);
for (var i = 0; i < decoder.frameCount; i++) {
(function (i) {
framesMasterPromise = framesMasterPromise.then(function () {
return decoder.getFrameAsync(i).then(function (bitmapFrame) {
return bitmapFrame.getPixelDataAsync().then(function (pixelDataContainer) {
var pixelData = pixelDataContainer.detachPixelData();
var newWidth = bitmapFrame.orientedPixelWidth,
newHeight = bitmapFrame.orientedPixelHeight;
if (bitmapFrame.orientedPixelWidth > MAX_WIDTH || bitmapFrame.orientedPixelHeight > MAX_HEIGHT) {
if (bitmapFrame.orientedPixelWidth > bitmapFrame.orientedPixelHeight) {
newWidth = MAX_WIDTH;
newHeight = Math.round(MAX_HEIGHT * bitmapFrame.orientedPixelHeight / bitmapFrame.orientedPixelWidth);
} else {
newWidth = Math.round(MAX_WIDTH * bitmapFrame.orientedPixelWidth / bitmapFrame.orientedPixelHeight);
newHeight = MAX_HEIGHT;
}
}
var biggestSide = Math.max(newWidth, newHeight);
var dpiForBothSides = biggestSide / RATIO_FOR_TWO_COLUMN_WORD_FIT;
encoder.setPixelData(
bitmapFrame.bitmapPixelFormat,
bitmapFrame.bitmapAlphaMode,
bitmapFrame.orientedPixelWidth,
bitmapFrame.orientedPixelHeight,
dpiForBothSides/*bitmapFrame.dpiX*/,
dpiForBothSides/*bitmapFrame.dpiY*/,
pixelData
);
encoder.bitmapTransform.scaledWidth = newWidth;
encoder.bitmapTransform.scaledHeight = newHeight;
if (i >= decoder.frameCount - 1)
return encoder.flushAsync();
return encoder.goToNextFrameAsync();
});
});
});
})(i);
}
return framesMasterPromise;
}).then(function () {
if (inStream) inStream.close();
if (outStream) outStream.close();
return resizedFile;
});
});
});
}
setPixelData() seems to be the only method that accept a resolution, but it has no effect on the resulting image. Actually, I can remove the whole encoder.setPixelData(...) part and see no change at all.
getPixelDataAsync() can take additionnal parameters but that does not seems to help.
Thanks for any help you could provide.
Got it. Found a bit of the solution here.
I was using BitmapEncoder.CreateForTranscodingAsync where I should have been using BitmapEncoder.CreateAsync, because the first is for simple transformation and does not allows you to change the image resolution (values are just ignored, as I noticed).
Here is the complete solution, with a bit of refactoring:
function resizePictureAsync(file) {
var inStream = null, outStream = null;
return file.openAsync(Windows.Storage.FileAccessMode.read).then(function (stream) {
inStream = stream;
return Windows.Graphics.Imaging.BitmapDecoder.createAsync(stream);
}).then(function (decoder) {
return Windows.Storage.ApplicationData.current.temporaryFolder.createFileAsync("temp-picture-resize", Windows.Storage.CreationCollisionOption.replaceExisting).then(function (resizedFile) {
return resizedFile.openAsync(Windows.Storage.FileAccessMode.readWrite).then(function (stream) {
outStream = stream;
outStream.size = 0;
var encoderCodecId = getEncoderCodecIdFromDecoderCodecId(decoder.decoderInformation.codecId);
return Windows.Graphics.Imaging.BitmapEncoder.createAsync(encoderCodecId, outStream);
}).then(function (encoder) {
return processAllBitmapFramesAsync(decoder, encoder);
}).then(function () {
return resizedFile;
});
});
}).then(null, function (err) {
var errorMessage = "Error transforming an image.\n" + err;
console.error(errorMessage);
return file;
}).then(function(resultFile) {
if (inStream) inStream.close();
if (outStream) outStream.close();
return resultFile;
});
};
function getEncoderCodecIdFromDecoderCodecId(decoderCodecId) {
var encoderCodecId;
switch (decoderCodecId) {
case Windows.Graphics.Imaging.BitmapDecoder.bmpDecoderId:
encoderCodecId = Windows.Graphics.Imaging.BitmapEncoder.bmpEncoderId;
break;
case Windows.Graphics.Imaging.BitmapDecoder.jpegDecoderId:
encoderCodecId = Windows.Graphics.Imaging.BitmapEncoder.jpegEncoderId;
break;
case Windows.Graphics.Imaging.BitmapDecoder.jpegXRDecoderId:
encoderCodecId = Windows.Graphics.Imaging.BitmapEncoder.jpegXREncoderId;
break;
case Windows.Graphics.Imaging.BitmapDecoder.gifDecoderId:
encoderCodecId = Windows.Graphics.Imaging.BitmapEncoder.gifEncoderId;
break;
case Windows.Graphics.Imaging.BitmapDecoder.pngDecoderId:
encoderCodecId = Windows.Graphics.Imaging.BitmapEncoder.pngEncoderId;
break;
case Windows.Graphics.Imaging.BitmapDecoder.tiffDecoderId:
encoderCodecId = Windows.Graphics.Imaging.BitmapEncoder.tiffEncoderId;
break;
default:
throw new Error("Impossible de déterminer le codec de l'encoder à partir de celui du decoder");
break;
}
return encoderCodecId;
}
function processAllBitmapFramesAsync(decoder, encoder) {
var framesMasterPromise = WinJS.Promise.wrap(null);
for (var i = 0; i < decoder.frameCount; i++) {
(function (i) {
framesMasterPromise = framesMasterPromise.then(function () {
return decoder.getFrameAsync(i).then(function (bitmapFrame) {
return processBitmapFrameAsync(bitmapFrame, encoder);
}).then(function () {
if (i >= decoder.frameCount - 1)
return encoder.flushAsync();
return encoder.goToNextFrameAsync();
});
});
})(i);
}
return framesMasterPromise;
}
function processBitmapFrameAsync(bitmapFrame, encoder) {
const MAX_HEIGHT = 1600,
MAX_WIDTH = 1600,
RATIO_FOR_TWO_COLUMN_WORD_FIT = 2.7;
var newWidth = bitmapFrame.orientedPixelWidth,
newHeight = bitmapFrame.orientedPixelHeight;
if (bitmapFrame.orientedPixelWidth > MAX_WIDTH || bitmapFrame.orientedPixelHeight > MAX_HEIGHT) {
if (bitmapFrame.orientedPixelWidth > bitmapFrame.orientedPixelHeight) {
newWidth = MAX_WIDTH;
newHeight = Math.round(MAX_HEIGHT * bitmapFrame.orientedPixelHeight / bitmapFrame.orientedPixelWidth);
} else {
newWidth = Math.round(MAX_WIDTH * bitmapFrame.orientedPixelWidth / bitmapFrame.orientedPixelHeight);
newHeight = MAX_HEIGHT;
}
}
var biggestSide = Math.max(newWidth, newHeight);
var dpiForBothSides = biggestSide / RATIO_FOR_TWO_COLUMN_WORD_FIT;
return bitmapFrame.getPixelDataAsync().then(function(pixelDataContainer) {
var pixelData = pixelDataContainer.detachPixelData();
encoder.setPixelData(
bitmapFrame.bitmapPixelFormat,
bitmapFrame.bitmapAlphaMode,
bitmapFrame.orientedPixelWidth,
bitmapFrame.orientedPixelHeight,
dpiForBothSides /*bitmapFrame.dpiX*/,
dpiForBothSides /*bitmapFrame.dpiY*/,
pixelData
);
encoder.bitmapTransform.scaledWidth = newWidth;
encoder.bitmapTransform.scaledHeight = newHeight;
});
}
Before I get into details, please take a look at the live example where this problem occurs - http://jsfiddle.net/66HFU/ (Script code at the bottom of this post)
Now if you would click on any image at last row, it would display these. However if you would click on upper row images, below row images are shown.
Further investigation shows that for somewhat reason the letter called function selector elements only get binded with event listener while the firstly called functions selector elements do not.
So, I would like to know is there are any ways to make the function call independent so the latter function call does not override first one (if that would fix the problem, of-course)?
The place where the event function gets bind on the element can be found in function f_AddEvents first lines.
And the the main function calls that are used to initialize Light Box is at the bottom of the code like this:
LightBox.init({
selector: "[data-simplbox='demo1']",
boxId: "simplbox"
});
LightBox.init({
selector: "[data-simplbox='demo2']",
boxId: "simplbox",
imageLoadStart: activityIndicatorOn,
imageLoadEnd: activityIndicatorOff
});
All code:
;(function (window, document, undefined) {
var docElem = document.documentElement;
var DomM = (function() {
var f_ToDOMStyle = function (p_Style) {
return p_Style.replace(/\-[a-z]/g, function (p_Style) {
return p_Style.charAt(1).toUpperCase();
});
};
return {
event: {
set: function (p_Element, p_Events, p_Function) {
var i = 0,
j = 0;
p_Events = p_Events.split(" ");
if (!p_Element.length) {
for (i = 0; i < p_Events.length; i++) {
p_Element.addEventListener(p_Events[i], p_Function, false);
}
} else {
for (i = 0; i < p_Element.length; i++) {
for (j = 0; j < p_Events.length; j++) {
p_Element[i].addEventListener(p_Events[j], p_Function, false);
}
}
}
}
},
css: {
set: function (p_Element, p_Style) {
var j;
if (!p_Element.length) {
for (j in p_Style) {
if (p_Style.hasOwnProperty(j)) {
j = f_ToDOMStyle(j);
p_Element.style[j] = p_Style[j];
}
}
} else {
for (var i = 0; i < p_Element.length; i++) {
for (j in p_Style) {
if (p_Style.hasOwnProperty(j)) {
j = f_ToDOMStyle(j);
p_Element[i].style[j] = p_Style[j];
}
}
}
}
}
}
};
}());
var _LightBox = {
f_MergeObjects: function (p_Original, p_Updates) {
for (var i in p_Updates) {
if (p_Updates.hasOwnProperty(i)) {
p_Original[i] = p_Updates[i];
}
}
return p_Original;
},
f_isFunction: function (p_Function) {
return !!(p_Function && p_Function.constructor && p_Function.call && p_Function.apply);
},
f_Initialize: function (p_Options) {
var base = this;
base.m_Options = base.f_MergeObjects(_LightBox.options, p_Options || {});
base.m_Elements = document.querySelectorAll(base.m_Options.selector);
base.m_ElementsLength = base.m_Elements.length - 1;
base.m_Body = document.getElementsByTagName("body")[0];
base.m_CurrentImageElement = false;
base.m_CurrentImageNumber = 0;
base.m_Direction = 1;
base.m_InProgress = false;
base.m_InstalledImageBox = false;
console.log(base.m_Elements);
// Check if hardware acceleration is supported and check if touch is enabled.
base.f_CheckBrowser();
// Adds events.
base.f_AddEvents();
},
f_CheckBrowser: function () {
var base = this,
isTouch = "ontouchstart" in window || window.navigator.msMaxTouchPoints || navigator.maxTouchPoints || false,
vendors = ["ms", "O", "Moz", "Webkit", "Khtml"],
rootStyle = docElem.style,
hardwareAccelerated = false;
if ("transform" in rootStyle) {
hardwareAccelerated = true;
} else {
while (vendors.length) {
if (vendors.pop() + "Transform" in rootStyle) {
hardwareAccelerated = true;
}
}
}
base.browser = {
"isHardwareAccelerated": hardwareAccelerated,
"isTouch": isTouch
};
},
f_AddEvents: function () {
var base = this;
// Add open image event on images.
for (var i = 0; i < base.m_Elements.length; i++) {
(function (i) {
base.m_Elements[i].addEventListener("click", function (event) {
event.preventDefault();
console.log(base.m_Elements[i]);
if (base.f_isFunction(base.m_Options.onImageStart)) {
base.m_Options.onImageStart();
}
base.f_OpenImage(i);
}, false);
})(i);
}
// Resize event for window.
window.addEventListener("resize", function (event) {
event.preventDefault();
base.f_SetImage();
}, false);
// Add keyboard support.
if (base.m_Options.enableKeyboard) {
var keyBoard = {
left: 37,
right: 39,
esc: 27
};
window.addEventListener("keydown", function (event) {
event.preventDefault();
if (base.m_CurrentImageElement) {
if (base.m_InProgress) {
return false;
}
switch (event.keyCode) {
case keyBoard.left:
// If the previous one is out of target range then go to the last image.
if ((base.m_CurrentImageNumber - 1) < 0) {
base.f_OpenImage(base.m_ElementsLength, "left");
} else {
base.f_OpenImage(base.m_CurrentImageNumber - 1, "left");
}
return false;
case keyBoard.right:
// If the next one is out of target range then go to the first image.
if ((base.m_CurrentImageNumber + 1) > base.m_ElementsLength) {
base.f_OpenImage(0, "right");
} else {
base.f_OpenImage(base.m_CurrentImageNumber + 1, "right");
}
return false;
case keyBoard.esc:
base.f_QuitImage();
return false;
}
}
return false;
}, false);
}
// Add document click event.
if (base.m_Options.quitOnDocumentClick) {
document.body.addEventListener("click", function (event) {
var target = event.target ? event.target : event.srcElement;
event.preventDefault();
if (target && target.id != "imagelightbox" && base.m_CurrentImageElement && !base.m_InProgress && base.m_InstalledImageBox) {
base.f_QuitImage();
return false;
}
return false;
}, false);
}
},
f_OpenImage: function (p_WhichOne, p_Direction) {
var base = this,
newFragment = document.createDocumentFragment(),
newImageElement = document.createElement("img"),
target = base.m_Elements[p_WhichOne].getAttribute("href");
if (base.m_CurrentImageElement) {
base.f_RemoveImage();
}
if (base.f_isFunction(base.m_Options.imageLoadStart)) {
base.m_Options.imageLoadStart();
}
base.m_InProgress = true;
base.m_InstalledImageBox = false;
base.m_Direction = typeof p_Direction === "undefined" ? 1 : p_Direction == "left" ? -1 : 1;
newImageElement.setAttribute("src", target);
newImageElement.setAttribute("alt", "LightBox");
newImageElement.setAttribute("id", base.m_Options.boxId);
newFragment.appendChild(newImageElement);
base.m_Body.appendChild(newFragment);
base.m_CurrentImageElement = document.getElementById(base.m_Options.boxId);
base.m_CurrentImageElement.style.opacity = "0";
base.m_CurrentImageNumber = p_WhichOne;
if (base.m_Options.quitOnImageClick) {
base.f_ImageClickEvent = function (event) {
event.preventDefault();
base.f_QuitImage();
};
base.m_CurrentImageElement.addEventListener("click", base.f_ImageClickEvent, false);
}
if (base.browser.isHardwareAccelerated) {
DomM.css.set(base.m_CurrentImageElement, base.f_AddTransitionSpeed(base.m_Options.animationSpeed));
}
base.f_SetImage();
DomM.css.set(base.m_CurrentImageElement, base.f_doTranslateX(50 * base.m_Direction + "px"));
setTimeout(function () {
if (base.browser.isHardwareAccelerated) {
setTimeout(function () {
DomM.css.set(base.m_CurrentImageElement, base.f_doTranslateX("0px"));
}, 50);
}
if (base.f_isFunction(base.m_Options.imageLoadEnd)) {
base.m_Options.imageLoadEnd();
}
}, 20);
setTimeout(function () {
base.m_InProgress = false;
base.m_InstalledImageBox = true;
}, base.m_Options.animationSpeed - 200);
},
f_SetImage: function () {
var base = this,
screenHeight = window.innerHeight || docElem.offsetHeight,
screenWidth = window.innerWidth || docElem.offsetWidth,
tmpImage = new Image(),
imageWidth, imageHeight, imageSizeRatio;
if (!base.m_CurrentImageElement) {
return;
}
tmpImage.onload = function () {
imageWidth = this.width;
imageHeight = this.height;
imageSizeRatio = imageWidth / imageHeight;
if (Math.floor(screenWidth/imageSizeRatio) > screenHeight) {
imageWidth = screenHeight * imageSizeRatio * 0.7;
imageHeight = screenHeight * 0.7;
} else {
imageWidth = screenWidth * 0.7;
imageHeight = screenWidth / imageSizeRatio * 0.7;
}
DomM.css.set(base.m_CurrentImageElement, {
"top": ((screenHeight - imageHeight) / 2) + "px",
"left": ((screenWidth - imageWidth) / 2) + "px",
"width": Math.floor(imageWidth) + "px",
"height": Math.floor(imageHeight) + "px",
"opacity": 1
});
};
tmpImage.src = base.m_CurrentImageElement.getAttribute("src");
},
f_RemoveImage: function () {
var base = this;
if (base.m_CurrentImageElement) {
if (base.f_isFunction(base.m_Options.quitOnImageClick)) {
base.m_CurrentImageElement.removeEventListener("click", base.f_ImageClickEvent, false);
}
base.m_CurrentImageElement.parentNode.removeChild(base.m_CurrentImageElement);
base.m_CurrentImageElement = false;
}
return false;
},
f_QuitImage: function () {
var base = this;
if (base.m_CurrentImageElement) {
setTimeout(function () {
DomM.css.set(base.m_CurrentImageElement, {
"opacity": 0,
"transition": ("opacity " + base.m_Options.fadeOutSpeed + "ms ease")
});
setTimeout(function () {
base.f_RemoveImage();
if (base.f_isFunction(base.m_Options.onImageQuit)) {
base.m_Options.onImageQuit();
}
}, base.m_Options.fadeOutSpeed);
}, 20);
}
},
f_IsValidSource: function (p_Src) {
return new RegExp().test(p_Src);
},
f_doTranslateX: function (p_Pixels) {
return {
"-webkit-transform": "translateX(" + p_Pixels + ")",
"-moz-transform": "translateX(" + p_Pixels + ")",
"-o-transform": "translateX(" + p_Pixels + ")",
"-ms-transform": "translateX(" + p_Pixels + ")",
"transform": "translateX(" + p_Pixels + ")"
};
},
f_AddTransitionSpeed: function (p_Speed) {
var base = this;
return {
"-webkit-transition": "transform " + p_Speed + "ms ease, opacity " + base.m_Options.fadeInSpeed + "ms ease",
"-moz-transition": "transform " + p_Speed + "ms ease, opacity " + base.m_Options.fadeInSpeed + "ms ease",
"-o-transition": "transform " + p_Speed + "ms ease, opacity " + base.m_Options.fadeInSpeed + "ms ease",
"transition": "transform " + p_Speed + "ms ease, opacity " + base.m_Options.fadeInSpeed + "ms ease"
};
}
};
_LightBox.options = {
selector: "[data-imagelightbox]",
boxId: "imagelightbox",
allowedTypes: "png|jpg|jpeg|gif",
quitOnImageClick: true,
quitOnDocumentClick: true,
enableKeyboard: true,
animationSpeed: 750,
fadeInSpeed: 500,
fadeOutSpeed: 200,
imageLoadStart: function () {},
imageLoadEnd: function () {},
onImageQuit: function () {},
onImageStart: function () {}
};
LightBox.init = function (p_Options) {
_LightBox.f_Initialize(p_Options);
};
})(window, document, window.LightBox = window.LightBox || {});
var activityIndicatorOn = function () {
var newE = document.createElement("div"),
newB = document.createElement("div");
newE.setAttribute("id", "imagelightbox-loading");
newE.appendChild(newB);
document.body.appendChild(newE);
},
activityIndicatorOff = function () {
var elE = document.getElementById("imagelightbox-loading");
elE.parentNode.removeChild(elE);
};
LightBox.init({
selector: "[data-simplbox='demo1']",
boxId: "simplbox"
});
LightBox.init({
selector: "[data-simplbox='demo2']",
boxId: "simplbox",
imageLoadStart: activityIndicatorOn,
imageLoadEnd: activityIndicatorOff
});
Your code is almost working. What you handled badly is the fact that you can perform several init. On each init, you overwrite some items, especially with this line :
base.m_Elements = document.querySelectorAll(base.m_Options.selector);
So base.m_Elements will only have the elements of the last init.
( Based on the name 'init' i wonder if the real use case wouldn't be to allow just one call of init... )
Quick-fix is to do one single init with :
LightBox.init({
selector: "[data-simplbox='demo1'],[data-simplbox='demo2']",
boxId: "simplbox"
});
(erase the two calls to init)
And here it works.
http://jsfiddle.net/gamealchemist/66HFU/1/
So i guess either you want to support several init, or (easier to maintain in fact), throw exception on multiple init and expect the lib user to write the right selector in the single init call.
Edit : Super quick fix for your issue : rather than having LightBox as a singleton, have it as a Class :
function LightBox( initArguments ) {
// something like what was done in init
}
LightBox.prototype = {
f_RemoveImage : function() {
} ,
f_OpenImage : function( ..., ... ) {
} ,
...
}
then you can call with no issue :
var demo1LB = new LightBox({ selector: "[data-simplbox='demo1']",
boxId: "simplbox" });
var demo2LB = new LightBox({ selector: "[data-simplbox='demo2']",
boxId: "simplbox" });
SOLVED
var player = 0;
if(player == 0)
{
document.getElementById("sp").src = "../image/start.png";
player = 1;
}
else if(player == 1)
{
document.getElementById("sp").src = "../image/stop.png";
player = 0;
}
I'm trying to make play/pause button in JavaScript.
The first text only version works fine using innerHtml but I need to use an image file for the final version.
I got 3 folders in my root dir:
image (where the image files are)
slide (where the php file are)
javascript (where the js file is placed)
In my php file:
<img src="../image/stop.png" id="sp">
<script type="text/javascript" src="../javascript/page1.js"></script>
In my js file:
if(document.getElementById("sp").src == "../image/stop.png") {
document.getElementById("sp").src = "../image/start.png";
} else if(document.getElementById("sp").src == "../image/start.png") {
document.getElementById("sp").src = "../image/stop.png";
}
I have search for a sulotion to this but I can't get it to work.
The old code for the text verison looks like this.
if(document.getElementById("sp").innerHTML == "Stop") {
document.getElementById("sp").innerHTML = "Start";
} else if(document.getElementById("sp").innerHTML == "Start") {
document.getElementById("sp").innerHTML = "Stop";
}
The code is in a function triggerd on an click event
Can someone please help me get this to work?
Here is the whloe js code.
I know this may not be optmal written but I'm very new to js
var CB =
{
addEvent : function(element, event, action)
{
if (element.addEventListener){
element.addEventListener(event, action, false);
}
else
{
element.attachEvent("on" + event, action);
}
}
}
Timer = function(callback, delay)
{
var timerId, start, remaining = delay;
this.pause = function()
{
window.clearTimeout(timerId);
remaining -= new Date() - start;
};
this.resume = function()
{
start = new Date();
timerId = window.setTimeout(callback, remaining);
};
this.resume();
};
var synlig = 0.0;
function visa(pic)
{
synlig += 0.1;
if(synlig < 1.0)
{
var x = String(synlig)
pic.style.opacity = x;
}
else
{
pic.style.opacity="1.0";
return;
}
setTimeout(function(){visa(pic)}, 120);
}
var ejSynlig = 1.0
function visaEJ(pic)
{
ejSynlig -= 0.1;
if(ejSynlig > 0.0)
{
var x = String(ejSynlig)
pic.style.opacity = x;
}
else
{
pic.style.opacity="0.0";
return;
}
setTimeout(function(){visaEJ(pic)}, 120);
}
var synlig2 = 0.0;
function visa2(pic2)
{
synlig2 += 0.1;
if(synlig2 < 1.0)
{
var x = String(synlig2)
pic2.style.opacity = x;
}
else
{
pic2.style.opacity="1.0";
return;
}
setTimeout(function(){visa2(pic2)}, 120);
}
var ejSynlig2 = 1.0
function visaEJ2(pic2)
{
ejSynlig2 -= 0.1;
if(ejSynlig2 > 0.0)
{
var x = String(ejSynlig2)
pic2.style.opacity = x;
}
else
{
pic2.style.opacity="0.0";
return;
}
setTimeout(function(){visaEJ2(pic2)}, 120);
}
var pic = document.getElementById("bild");
var t1s = new Timer(function(){visa(pic)}, 5000);
var t1h = new Timer(function(){visaEJ(pic)}, 11000);
var pic2 = document.getElementById("bild2");
var t2s = new Timer(function(){visa2(pic2)}, 11500);
var t2h = new Timer(function(){visaEJ2(pic2)}, 15000);
function imgs()
{
var p = document.getElementById("sp");
var x1, y1, x2, y2;
if(document.getElementById("sp").src == "../image/stop.png")
{
x1 = t1s.pause();
y1 = t1h.pause();
x2 = t2s.pause();
y2 = t2h.pause();
}
else if(document.getElementById("sp").src == "../image/start.png")
{
x1 = t1s.resume();
y1 = t1h.resume();
x2 = t2s.resume();
y2 = t2h.resume();
}
CB.addEvent(p, "click", x1);
CB.addEvent(p, "click", y1);
CB.addEvent(p, "click", x2);
CB.addEvent(p, "click", y2);
}
function snd()
{
var sndP = document.getElementById("sndP");
function playS()
{
sndP.volume = 0.5;
sndP.play();
}
function pauseS()
{
sndP.pause();
}
var p = document.getElementById("sp");
var y;
if(document.getElementById("sp").src == "../image/stop.png")
{
y = pauseS();
}
else if(document.getElementById("sp").src == "../image/start.png")
{
y = playS();
}
CB.addEvent(p, "click", y);
}
function theshit()
{
imgs();
snd();
if(document.getElementById("sp").src == "../image/stop.png")
{
document.getElementById("sp").src = "../image/start.png";
}
else if(document.getElementById("sp").src == "../image/start.png")
{
document.getElementById("sp").src = "../image/stop.png";
}
}
var sp = document.getElementById("sp");
CB.addEvent(sp, "click", theshit);
sndP.volume = 0.5;
sndP.play();
if(document.getElementById("sp").src == "../image/stop.png")
{
document.getElementById("sp").setAttribute("src","../image/start.png");
}
else if(document.getElementById("sp").src == "../image/start.png")
{
document.getElementById("sp").setAttribute("src","../image/stop.png");
}
So you want to toggle the image when clicked?
if you set something to src and then get it, it might look a little bit different.
a better solution, than to check if something has a specific url, you could save the isPlaying variable manually. this way you would writeonly to the DOM, which is faster, then reading the src value manually all the time.
var isPlaying = false;
var stopImg = "../images/stop.png";
var playImg = "../images/start.png";
var el = document.getElementById("sp");
$("button").click(function() {
// toggle
el.src = isPlaying ? stopImg : playImg;
// also toggle the var
isPlaying = !isPlaying;
});
even a better way is to do it using CSS and for example a background-image...
button {
/*default state*/
background-image : url('/images/play.png');
}
button.isPlaying {
/*state when playing*/
background-image : url('/images/stop.png');
}
and then in JS
$("button").click(function() {
$(this).toggleClass("isPlaying");
});
Here is an excerpt of my code. You can ignore most of it: the bit of concern is with the refreshDimensions method, the call to said method inside zoomTo, and the block of code after that call.
function refreshDimensions(node) {
_("refreshdimensions");
t = $("#contents");
var other = $(selectednode).parent().parent(":not(#contents)");
if(!other.length) {
other = selectednode || zoomednode || start;
t.width("100%");
} else {
t.width("100%");
t.width((t.width() + other.position().left));
}
t.height($(other).position().top);
/* Begin animating */
t.animate({ fontSize: zoom }, {duration: 0, queue: false });
//
}
function zoomTo(node, select) {
var oldzoom, zoomdepth, t;
oldzoom = zoomednode;
if($(node)[0] != $(zoomednode)[0]) {
savedepth = t = zoomdepth = $(node).parents("ul").length;
if(!zoomednode)
zoomednode = topChapter;
$(zoomednode).toggleClass("zoomednode", false);
if(!node)
node = topChapter;
/* capture values */
var sz;
var capp = cBaseSz.slice((zoom = zoomnum = sz = parseFloat(cBaseSz)+"").length);
/* end capture */
while(--t > 0) {
zoomnum = (zoom *= 1.15);
}
zoom += capp;
zoomdepth -= $(zoomednode).parents("ul").length;
if(zoomdepth < 0)
zoomdepth *= -1;
zoomednode = node;
zoomednode.toggleClass("zoomednode", true);
switch(select) {
case 0:
case false:
default:
break;
case true:
case 1:
toggleNode(selectednode, false);
toggleNode(node, true);
break;
case 2:
toggleNode(zoomednode, false);
zoomednode = 0;
}
/* Handle showing/hiding */
//////////////////////////////
//
var showzoom = 1, showselect = 1, showidea = 1, seldepth, zdepth, showlist, hidelist = {};
/* This is the 'brute force' way of doing it, horribly inefficient */
if(zoomednode)
zdepth = $(zoomednode).parents(".chapter").length;
if(selectednode)
seldepth = $(selectednode).parents(".chapter").length;
else
seldepth = zdepth;
if(!seldepth)
seldepth = zdepth = 0;
showlist=$(".chapter, .idea").filter( function() {
if($(this).parents("li").length < (zdepth+showzoom))
return true;
else {
hidelist = $(hidelist).add(this);
return false;
}
});
$(showlist).show()/*.not(hidelist)*/;
if(hidelist && hidelist.length) {
$(hidelist).hide();
}
/* End showing/hiding */
refreshDimensions(node);
if(node) {
_("top: " + $(zoomednode).position().top);
$("html,body").stop().animate(
{ scrollTop: $(zoomednode).position().top - topAdjust }, {duration: 60+60*zoomdepth, queue: false }, 0);
}
}
else {
var dest;
if($(zoomednode).parents(".chapter").length > 1)
dest = $(zoomednode).parent().parent().prevAll(".chapter:first .chapterheading:first");
else {
// if($(zoomednode)[0] != $("#contents")[0]) {
toggleNode(selectednode, false);
dest = $("#contents");
// } else
// dest = $(start);
}
zoomTo(dest, 0);
}
}
So my problem is that when I move the bit of code after the call to refreshDimensions (the block beginning with 'if(node) {'), into refreshDimensions (at the end), the desired effect stops working. I have dumped all the variables that the line uses into the console and they are consistent across both instances, yet when I move the code to refreshDimensions my page gets 'trapped' at the top of the screen and won't scroll at all. This really has me stumped as everything points to that it should work exactly the same...
turns out it was because 'zoomdepth' should have been a global rather than local variable.
Im looking for a jQuery pluging (or code/guide) that does this: http://codecanyon.net/item/jquery-css3-sticky-mega-menu-bar/full_screen_preview/239093
This one is not free
Note: Notice the navigation bar is not placed at the top from the beginning. It sticks once the viewport "hits" it.
Anthony Garand also has a pretty sticky plugin - All free and actually maintained on GitHub:
jQuery Sticky Plugin
You could reverse engineer #genesis link which is the exact script you are looking for (no it is not hard)
I couldn't find a url for a non-minified version.. so here it is.
(function ($) {
$.fn.stickyMenubar = function (o) {
o = $.extend({
top: null,
floatingDiv: null,
floatingDivBackground: false,
megaMenu: true,
onScroll: function () {},
onLeaveTop: function () {},
sensitivity: 7,
padding: 5,
container_width: 960
}, o || {});
var setLiActions = function (t, lvl) {
var parent_ul = t.children('ul:first');
if (lvl > 0) {
t.addClass('inner_menu').hide();
} else {
if (!o.floatingDivBackground) {
t.addClass('smenubar_background');
}
}
t.mouseleave(function () {
$(this).children('li').children('ul').hide();
});
t.children('li').each(function () {
var li = $(this);
var class_parent = '';
var class_child = '';
var uls = li.children('ul');
if (uls.length) {
uls.each(function () {
setLiActions($(this), lvl + 1);
})
if (lvl == 0) {
li.children('a:first').addClass('arrow_down');
} else {
li.children('a:first').addClass('arrow_right');
}
if (!$.fn.hoverIntent) {
alert('hoverIntent javascript library must be included');
return;
}
var config = {
over: function () {
if (lvl == 0) {
$(this).parent().children('li').not($(this)).children('ul').hide();
var inner_ul = li.children('ul:first');
var pos = li.position();
var pos_ul = inner_ul.position();
var top_c = pos.top + li.height();
if (inner_ul.hasClass('show2left')) {
var left_c = pos.left - inner_ul.width() + li.width() + (o.padding * 2);
class_parent = 'inuseleft';
class_child = 'inusechildleft';
class_panel = 'left_slide';
inner_ul.addClass('topleftradius')
} else if (inner_ul.hasClass('mega_menu')) {
var left_c = 0 + ($(document).width() / 2) - (o.container_width / 2);
class_parent = 'inusemega', class_child = 'inusechildmega';
class_panel = 'mega_slide';
inner_ul.addClass('topleftradius').addClass('toprightradius');
} else {
var left_c = pos.left;
class_parent = 'inuse';
class_child = 'inusechild';
class_panel = 'right_slide';
inner_ul.addClass('toprightradius');
}
if (!$.browser.msie || ($.browser.msie && ($.browser.version > 7.0))) {
if (inner_ul.width() <= (li.width() + (o.padding * 2))) {
inner_ul.css('width', li.width() + (o.padding * 2));
inner_ul.removeClass('topleftradius').removeClass('toprightradius');
}
}
inner_ul.stop(true, true).css({
top: top_c,
left: left_c
}).addClass(class_panel).slideDown(150);
li.addClass(class_child);
} else {
var inner_ul = li.children('ul');
var pos = li.position();
var pos_ul = inner_ul.position();
var top_c = pos.top;
if (inner_ul.hasClass('show2left')) {
var left_c = pos.left - inner_ul.width() + li.width() - 1;
class_parent = 'inuseleft';
class_child = 'inusechildleft';
class_panel = 'left_slide';
} else {
var left_c = pos.left + li.width();
if ($.browser.mozilla) {
left_c--;
}
class_parent = 'inuse';
class_child = 'inusechild';
class_panel = 'right_slide';
}
inner_ul.css({
top: top_c,
left: left_c
}).addClass(class_panel).css({
'white-space': 'nowrap'
}).stop(true, true).animate({
width: 'toggle'
}, 300);
li.addClass(class_child);
}
},
sensitivity: o.sensitivity,
timeout: 200,
out: function () {
li.stop(true, true).removeClass(class_child).children('ul').hide();
}
};
li.each(function () {
$(this).hoverIntent(config);
$(this).mouseleave(function () {
if (lvl == 0) {
$(this).children('ul').hide();
}
});
});
} else {
li.mouseenter(function () {
li.stop(true, true).addClass(class_parent);
});
li.mouseleave(function () {
li.stop(true, true).removeClass(class_parent).children('ul').hide();
});
}
});
}
return this.each(function () {
var t = $(this);
t.addClass('smenubar');
if (!o.floatingDiv) {
var floatingDiv = t;
} else {
var floatingDiv = o.floatingDiv;
floatingDiv.css({
width: '100%'
});
}
var top_Y = 0;
if (!o.top) {
top_Y = floatingDiv.position().top;
} else {
top_Y = o.top;
}
if (o.floatingDivBackground) {
floatingDiv.addClass('smenubar_background');
t.css({
'border-bottom': 'none'
});
}
$(window).scroll(function () {
if ($(this).scrollTop() >= top_Y) {
if (!($.browser.msie && ($.browser.version <= 7.0))) {
floatingDiv.addClass('float_top');
o.onLeaveTop.call(this);
}
} else {
floatingDiv.removeClass('float_top').removeClass('float_top_ie7');
o.onScroll.call(this);
}
var open_menu = $('.inner_menu:visible');
var parent_li = open_menu.parent();
var pos = parent_li.position();
open_menu.css({
top: pos.top + parent_li.height()
});
});
t.find('.toggle_block').slideToggle();
t.find('.toggle_handle').html('...').css('text-align', 'center');
t.find('a').click(function () {
if ($(this).hasClass('toggle_handle')) {
var prev = $(this).parent().prev('.toggle_block');
prev.slideToggle().prevUntil(':not(.toggle_block)').slideToggle();
}
if ($(this).attr('href') == '#') {
event.preventDefault();
return;
}
});
if (o.megaMenu == true) {
setLiActions(t, 0);
}
});
};
})(jQuery);
play around with it. generally these plugins are very scale-able and customize-able so there is a bunch of junk code in there. The majority of what you want seems to be encased in
(window).scroll(function () {
if ($(this).scrollTop() >= top_Y) {
if (!($.browser.msie && ($.browser.version <= 7.0))) {
floatingDiv.addClass('float_top');
o.onLeaveTop.call(this);
}
} else {
floatingDiv.removeClass('float_top').removeClass('float_top_ie7');
o.onScroll.call(this);
}
var open_menu = $('.inner_menu:visible');
var parent_li = open_menu.parent();
var pos = parent_li.position();
open_menu.css({
top: pos.top + parent_li.height()
});
});