I have a parallax function for a slide section of my page with 3 background images. For some reasons it is appearing quite laggy and slow when I scroll and sometimes it's hard to scroll to the 3rd background image or if I'm already at 3rd background I can't seem to scroll up again. If I scrolled up to the first background I seem to be stuck on this section and I can't go to the section above it. Not sure where I went wrong.
Here's my js:
(function ($) {
var types = ['DOMMouseScroll', 'mousewheel'];
if ($.event.fixHooks) {
for (var i = types.length; i;) {
$.event.fixHooks[types[--i]] = $.event.mouseHooks;
}
}
$.event.special.mousewheel = {
setup: function () {
if (this.addEventListener) {
for (var i = types.length; i;) {
this.addEventListener(types[--i], handler, false);
}
} else {
this.onmousewheel = handler;
}
}
, teardown: function () {
if (this.removeEventListener) {
for (var i = types.length; i;) {
this.removeEventListener(types[--i], handler, false);
}
} else {
this.onmousewheel = null;
}
}
};
$.fn.extend({
mousewheel: function (fn) {
return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
}
, unmousewheel: function (fn) {
return this.unbind("mousewheel", fn);
}
});
function handler(event) {
var orgEvent = event || window.event
, args = [].slice.call(arguments, 1)
, delta = 0
, returnValue = true
, deltaX = 0
, deltaY = 0;
event = $.event.fix(orgEvent);
event.type = "mousewheel";
if (orgEvent.wheelDelta) {
delta = orgEvent.wheelDelta / 120;
}
if (orgEvent.detail) {
delta = -orgEvent.detail / 3;
}
deltaY = delta;
if (orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS) {
deltaY = 0;
deltaX = -1 * delta;
}
if (orgEvent.wheelDeltaY !== undefined) {
deltaY = orgEvent.wheelDeltaY / 120;
}
if (orgEvent.wheelDeltaX !== undefined) {
deltaX = -1 * orgEvent.wheelDeltaX / 120;
}
args.unshift(event, delta, deltaX, deltaY);
return ($.event.dispatch || $.event.handle).apply(this, args);
}
})(jQuery);
var Parallax = {
utils: {
doSlide: function (section) {
var top = section.position().top;
$('#section-wrapper').stop().animate({
top: -top
}, 600, 'linear', function () {
section.addClass('slided').siblings('div.section').removeClass('slided');
});
}
}
, fn: {
setHeights: function () {
$('div.section').height($(window).height());
}
, onSiteScroll: function () {
var section = null;
$('#section-wrapper').mousewheel(function (event, delta) {
event.preventDefault();
if (delta < 0) {
section = ($('.slided').length) ? $('.slided') : $('#section-1');
var next = (section.next().length) ? section.next() : $('#section-1');
Parallax.utils.doSlide(next);
} else if (delta > 0) {
section = ($('.slided').length) ? $('.slided') : $('#section-1');
var prev = (section.prev().length) ? section.prev() : $('#section-1');
Parallax.utils.doSlide(prev);
}
});
}
},
init: function () {
for (var prop in this.fn) {
if (typeof this.fn[prop] === 'function') {
this.fn[prop]();
}
}
}
};
Parallax.init();
The css here:
#site {
width: 100%;
height: 100%;
min-height: 100%;
}
#section-wrapper {
position: relative;
width: 100%;
height: 100%;
min-height: 100%;
}
div.section {
width: 100%;
position: relative;
height: 100%;
min-height: 100%;
}
#section-1 {
background: url("../img/teavana/slide1.png");
}
#section-2 {
background: url("../img/teavana/slide2.png");
}
#section-3 {
background: url("../img/teavana/slide3.png");
}
And this is the html for the section:
<div id="site">
<div id="section-wrapper">
<div class="section" id="section-1"></div>
<div class="section" id="section-2"></div>
<div class="section" id="section-3"></div>
</div>
</div>
Related
I have completed 2048 clone and its can be played on pc's and laptops but not on phones. I want to make it playble on both the devices is it possible to add touch event handler with keystrokes handler to the same version Or I have to make a complete different version for phone? if it can be done in the same version please tell how it can be done.
Thanks.
//Export Grid js
const GRID_SIZE = 4
const CELL_SIZE = 20
const CELL_GAP = 2
class Grid {
//making cells private is so that it can be only accesible in grid class
#cells
constructor(gridElement) {
gridElement.style.setProperty("--grid-size", GRID_SIZE)
gridElement.style.setProperty("--cell-size", `${CELL_SIZE}vmin`)
gridElement.style.setProperty("--cell-gap", `${CELL_GAP}vmin`)
this.#cells = createCellElements(gridElement).map((cellElement, index) => {
return new Cell(
cellElement,
index % GRID_SIZE,
Math.floor(index / GRID_SIZE)
)
})
}
get cells() {
return this.#cells
}
get cellsByRow() {
return this.#cells.reduce((cellGrid, cell) => {
cellGrid[cell.y] = cellGrid[cell.y] || []
cellGrid[cell.y][cell.x] = cell
return cellGrid
}, [])
}
get cellsByColumn() {
return this.#cells.reduce((cellGrid, cell) => {
cellGrid[cell.x] = cellGrid[cell.x] || []
cellGrid[cell.x][cell.y] = cell
return cellGrid
}, [])
}
get #emptyCells() {
return this.#cells.filter(cell => cell.tile == null)
}
// it will return which ever cell is empty
randomEmptyCell() {
const randomIndex = Math.floor(Math.random() * this.#emptyCells.length)
return this.#emptyCells[randomIndex]
}
}
class Cell {
#cellElement
#x
#y
#tile
#mergeTile
constructor(cellElement, x, y) {
this.#cellElement = cellElement
this.#x = x
this.#y = y
}
get x() {
return this.#x
}
get y() {
return this.#y
}
get tile() {
return this.#tile
}
set tile(value) {
this.#tile = value
if (value == null) return
this.#tile.x = this.#x
this.#tile.y = this.#y
}
get mergeTile() {
return this.#mergeTile
}
set mergeTile(value) {
this.#mergeTile = value
if (value == null) return
this.#mergeTile.x = this.#x
this.#mergeTile.y = this.#y
}
canAccept(tile) {
return (
this.tile == null ||
(this.mergeTile == null && this.tile.value === tile.value)
)
}
mergeTiles() {
if (this.tile == null || this.mergeTile == null) return
this.tile.value = this.tile.value + this.mergeTile.value
this.mergeTile.remove()
this.mergeTile = null
}
}
function createCellElements(gridElement) {
const cells = []
for (let i = 0; i < GRID_SIZE * GRID_SIZE; i++) {
const cell = document.createElement("div")
cell.classList.add("cell")
cells.push(cell)
gridElement.append(cell)
}
return cells
}
//Export Tile js
class Tile {
#tileElement
#x
#y
#value
// randomly set 2 or 4
constructor(tileContainer, value = Math.random() > 0.5 ? 2 : 4) {
this.#tileElement = document.createElement("div")
this.#tileElement.classList.add("tile")
tileContainer.append(this.#tileElement)
this.value = value
}
get value() {
return this.#value
}
set value(v) {
this.#value = v
this.#tileElement.textContent = v
// to determine how many times a number has be raised to power of 2
const power = Math.log2(v)
const backgroundLightness = 100 - power * 9
this.#tileElement.style.setProperty("--background-light", `${backgroundLightness}%`)
this.#tileElement.style.setProperty("--text-light", `${backgroundLightness <= 50 ? 90 : 10}%`)
}
set x(value) {
this.#x = value
this.#tileElement.style.setProperty("--x", value)
}
set y(value) {
this.#y = value
this.#tileElement.style.setProperty("--y", value)
}
remove() {
this.#tileElement.remove()
}
waitForTransition(animation = false) {
return new Promise(resolve => {
this.#tileElement.addEventListener(
animation ? "animationend" : "transitionend",
resolve,
{
once: true,
}
)
})
}
}
//brain js
//import Grid from "./Grid.js";
//import Tile from "./Tile.js";
const board = document.getElementById("holder");
const grid = new Grid(board)
grid.randomEmptyCell().tile = new Tile(board)
grid.randomEmptyCell().tile = new Tile(board)
setupInput()
function setupInput() {
window.addEventListener("keydown", handleInput, { once: true })
}
async function handleInput(e) {
switch (e.key) {
case "ArrowUp":
if (!canMoveUp()) {
setupInput()
return
}
await moveUp()
break
case "ArrowDown":
if (!canMoveDown()) {
setupInput()
return
}
await moveDown()
break
case "ArrowLeft":
if (!canMoveLeft()) {
setupInput()
return
}
await moveLeft()
break
case "ArrowRight":
if (!canMoveRight()) {
setupInput()
return
}
await moveRight()
break
default:
setupInput()
return
}
grid.cells.forEach(cell => cell.mergeTiles())
const newTile = new Tile(board)
grid.randomEmptyCell().tile = newTile
if (!canMoveUp() && !canMoveDown() && !canMoveLeft() && !canMoveRight()) {
newTile.waitForTransition(true).then(() => {
alert("You lose")
})
return
}
setupInput()
}
function moveUp() {
return slideTiles(grid.cellsByColumn)
}
function moveDown() {
return slideTiles(grid.cellsByColumn.map(column => [...column].reverse()))
}
function moveLeft() {
return slideTiles(grid.cellsByRow)
}
function moveRight() {
return slideTiles(grid.cellsByRow.map(row => [...row].reverse()))
}
function slideTiles(cells) {
return Promise.all(
cells.flatMap(group => {
const promises = []
for (let i = 1; i < group.length; i++) {
const cell = group[i]
if (cell.tile == null) continue
let lastValidCell
for (let j = i - 1; j >= 0; j--) {
const moveToCell = group[j]
if (!moveToCell.canAccept(cell.tile)) break
lastValidCell = moveToCell
}
if (lastValidCell != null) {
promises.push(cell.tile.waitForTransition())
if (lastValidCell.tile != null) {
lastValidCell.mergeTile = cell.tile
} else {
lastValidCell.tile = cell.tile
}
cell.tile = null
}
}
return promises
})
)
}
function canMoveUp() {
return canMove(grid.cellsByColumn)
}
function canMoveDown() {
return canMove(grid.cellsByColumn.map(column => [...column].reverse()))
}
function canMoveLeft() {
return canMove(grid.cellsByRow)
}
function canMoveRight() {
return canMove(grid.cellsByRow.map(row => [...row].reverse()))
}
function canMove(cells) {
return cells.some(group => {
return group.some((cell, index) => {
if (index === 0) return false
if (cell.tile == null) return false
const moveToCell = group[index - 1]
return moveToCell.canAccept(cell.tile)
})
})
}
*,
*::before,
*::after {
box-sizing: border-box;
font-family: Arial, Helvetica, sans-serif;
}
body {
background-color: black;
display: flex;
margin: 0;
justify-content: center;
align-items: center;
height: 100vh;
font-size: 7.5vmin;
}
#holder {
display: grid;
background-color: #ccc;
position: relative;
grid-template-columns: repeat(var(--grid-size), var(--cell-size));
grid-template-rows: repeat(var(--grid-size), var(--cell-size));
gap: var(--cell-gap);
padding: var(--cell-gap);
border-radius: 1vmin;
}
.cell {
background-color: #aaa;
border-radius: 1vmin;
}
.tile {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
width: var(--cell-size);
height: var(--cell-size);
border-radius: 1vmin;
top: calc(var(--y) * (var(--cell-size) + var(--cell-gap)) + var(--cell-gap));
left: calc(var(--x) * (var(--cell-size) + var(--cell-gap)) + var(--cell-gap));
font-weight: bold;
background-color: hsl(271, 50%, var(--background-light));
color: hsl(200, 25%, var(--text-light));
animation: wow 200ms ease-in-out;
transition: 100ms ease-in-out;
}
#keyframes wow {
0% {
opacity: .5;
transform: scale(0);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>2048</title>
<link rel="stylesheet" href="game.css">
<script src="brain.js" type="module"></script>
</head>
<body>
<div id="holder">
</div>
</body>
</html>
I need to link these two codes so that when the "isElementInViewport" function returns true to trigger the "inviewport" event:
let inViewportEvent = document.createEvent("Event");
inViewportEvent.initEvent("inviewport", true, true);
document.addEventListener("inviewport", (e) => {
console.log(`${e.target} in viewport!`)
}, false);
document.dispatchEvent(inViewportEvent);
and this function to detect if a element are in viewport:
const isElementInViewport = el => {
let rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
We must use CustomEvent constructor to create a new custom event, and then use dispatchEvent to trigger it...
const inViewportCustomEvent = new CustomEvent('inviewport', {
detail: {
/* put the data to be carried here*/
}
});
document.dispatchEvent(inViewportCustomEvent);
Illustration
const isElementInViewport = (el) => {
let rect = el.getBoundingClientRect();
// console.log(rect);
const isIn = (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
console.log('[isElementInViewport]', isIn, {
top: rect.top,
right: rect.right,
left: rect.left,
bottom: rect.bottom,
innerHeight: window.innerHeight,
clientHeight: document.documentElement.clientHeight,
innerWidth: window.innerWidth,
clientWidth: document.documentElement.clientWidth
});
return isIn;
};
const observer_callback = (entries, observer) => {
entries.filter(entry => isElementInViewport(entry.target))
.forEach(entry => {
console.log("We got something");
const inViewportCustomEvent = new CustomEvent('inviewport', {
detail: {
target: entry
/* put the data to be carried here*/
}
});
document.dispatchEvent(inViewportCustomEvent);
});
};
function create_observer() {
let options = {
root: document,
rootMargin: "5px"
};
return new IntersectionObserver(observer_callback, options);
}
const outermost = document.querySelector("#outermost");
const fill_counter = document.querySelector("#fill_counter");
const filler = document.querySelector("#filler");
const fill_clearer = document.querySelector("#fill_clearer");
const highlighted_index = document.querySelector("#highlighted_index");
function fill_squares(num_squares) {
outermost.append(...new Array(num_squares).fill(0).map((_, index) => create_square(index)));
function create_square(index) {
const divEle = document.createElement("div");
divEle.setAttribute("data-index", index);
divEle.classList.add("square");
divEle.onclick = (event) => {
event.target.classList.toggle("square");
event.target.classList.toggle("highlighted_square");
}
return divEle;
}
}
function highlight_square(index) {
const selected_square = outermost.querySelector(`[data-index="${index}"]`);
if (selected_square) {
if (!selected_square.classList.contains("highlighted_square")) {
selected_square.classList.toggle("square");
selected_square.classList.toggle("highlighted_square");
}
}
}
function highlight_squares(indexes) {
if (indexes && indexes.length) {
indexes.forEach(index => highlight_square(index));
}
}
function clear_children(parentElement) {
var e = parentElement;
var first = e.firstElementChild;
while (first) {
first.remove();
first = e.firstElementChild;
}
}
resetter.onclick = (event) => {
fill_counter.value = outermost.getAttribute("data-fill-count");
highlighted_index.value = +outermost.getAttribute("data-highlight-index");
reset();
}
filler.onclick = (event) => {
reset();
}
highlighter.onclick = (event) => {
const highlightedIndex = +highlighted_index.value < +event.target.min ? +event.target.value : +highlighted_index.value;
if (!isNaN(highlightedIndex)) {
highlight_square(highlightedIndex);
}
}
fill_counter.onchange = (event) => {
let current_value = +event.target.value;
if (!isNaN(current_value)) {
if (current_value < +event.target.min) {
event.target.value = +event.target.min;
}
}
}
highlighted_index.onchange = (event) => {
let current_value = +event.target.value;
if (!isNaN(current_value)) {
if (current_value < +event.target.min) {
event.target.value = +event.target.min;
}
if (+event.target.value === +event.target.min) {
event.target.value = +event.target.min;
}
}
}
function reset() {
clear_children(outermost);
fill_squares(+fill_counter.value);
}
function setup_listener() {
document.addEventListener("inviewport", (e) => {
console.log(`${e.detail.target} in viewport!`)
}, false);
}
reset();
highlight_squares([19, 50, 35]);
setup_listener();
const observer = create_observer();
outermost.querySelectorAll('.highlighted_square').forEach(square => observer.observe(square));
.input_region {
margin: 5px;
}
.input_region label {
display: inline-block;
}
.action_input {
padding: 10px;
}
.highlighted_square {
background: yellow
}
.num_input {
height: 30px;
width: 50px;
padding: 5px;
}
.square {
background: magenta
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(5rem, 1fr));
grid-auto-rows: 1fr;
}
.grid::before {
content: '';
width: 0;
padding-bottom: 100%;
grid-row: 1 / 1;
grid-column: 1 / 1;
}
.grid>*:first-child {
grid-row: 1 / 1;
grid-column: 1 / 1;
}
/* Just to make the grid visible */
.grid>* {
// background: rgba(0, 0, 0, 0.1);
border: 1px white solid;
}
<section>
<div class="input_region">
<input class="num_input" id="fill_counter" type="number" value="1000" min="10" />
<button id="filler" class="action_input">FILL</button>
</div>
<div class="input_region">
<input class="num_input" id="highlighted_index" type="number" value="10" min="0" />
<button id="highlighter" class="action_input">HIGHLIGHT</button>
</div>
<div class="input_region">
<button class="action_input" id="resetter">RESET</button>
</div>
</section>
<section>
<div id="outermost" class="grid" data-fill-count="1000" data-highlight-index="100"></div>
</section>
How do I perform an animated transformation on text while performing a fade in effect during the animated transformation?
// ——————————————————————————————————————————————————
// TextScramble
// ——————————————————————————————————————————————————
class TextScramble {
constructor(elm, numWords) {
this.el = el
this.numWords = numWords;
this.chars = '!<>-_\\/[]{}—=+*^?#1234567890________'
this.update = this.update.bind(this)
}
setText(newText) {
const oldText = this.el.innerText
const length = Math.max(oldText.length, newText.length)
const promise = new Promise((resolve) => this.resolve = resolve)
this.queue = []
for (let i = 0; i < length; i++) {
const from = oldText[i] || ''
const to = newText[i] || ''
const start = Math.floor(Math.random() * 40)
const end = start + Math.floor(Math.random() * 40)
this.queue.push({ from, to, start, end })
}
cancelAnimationFrame(this.frameRequest)
this.frame = 0
this.update()
return promise
}
update() {
let output = ''
let complete = 0
for (let i = 0, n = this.queue.length; i < n; i++) {
let { from, to, start, end, char } = this.queue[i]
if (this.frame >= end) {
complete++
output += to
} else if (this.frame >= start) {
if (!char || Math.random() < 0.28) {
char = this.randomChar()
this.queue[i].char = char
}
output += `<span class="dud">${char}</span>`
} else {
output += from
}
}
this.el.innerHTML = output
if (complete === this.queue.length) {
this.resolve()
}
else {
this.frameRequest = requestAnimationFrame(this.update)
this.frame++
}
}
randomChar() {
return this.chars[Math.floor(Math.random() * this.chars.length)]
}
}
// ——————————————————————————————————————————————————
// Example
// ——————————————————————————————————————————————————
const phrases = {
'Coding' : 'none',
'With' : 'none',
'Muhammad': 'none',
'Coding With Muhammad' : 'fade'
}
let phraseValues = Object.keys(phrases);
const el = document.querySelector('.text')
const fx = new TextScramble(el, phraseValues.length)
let counter = 0
let animation = phraseValues[0];
let animate = () => {
return function(callback) {
document.querySelector(".text").animate([
// keyframes
{ opacity: '0' },
{ opacity: '1' }
], {
// timing options
duration: 3500,
iterations: 1
});
callback();
}
}
const next = () => {
fx.setText(phraseValues[counter]).then(() => {
if (counter <= phraseValues.length)
setTimeout(next, 800)
else {
animation = phrases[phraseValues[counter]]
setTimeout(animate(next), 800)
}
})
counter = (counter + 1) % phraseValues.length
}
next()
html, body {
font-family: 'Roboto Mono', monospace;
background: #212121;
height: 100%;
}
.container {
height: 100%;
width: 100%;
justify-content: center;
align-items: center;
display: flex;
}
.text {
font-weight: 100;
font-size: 28px;
color: #FAFAFA;
}
.dud {
color: #757575;
}
.fadeIn {
animation: fade 10s;
}
<div class="container">
<div class="text"></div>
</div>
I was very close:
I moved the callback invocation statement above the closure return statement below it. I left the animation keyframes as is.
Finally I modified the setTimeout in the phrase to be animated, to be as follows:
I placed a next and animate as callbacks in the setTimeout together to be called back in cascade sequence.
I used a anonymous function definition using arrow notation.
On animate (the function I wrote) I passed in the fx.update function definition as the callback, and invoked the closure function returned animate as the Higher Order Function, like so.
See Results!
// ——————————————————————————————————————————————————
// TextScramble
// ——————————————————————————————————————————————————
class TextScramble {
constructor(elm, numWords) {
this.el = el
this.numWords = numWords;
this.chars = '!<>-_\\/[]{}—=+*^?#1234567890________'
this.update = this.update.bind(this)
}
setText(newText) {
const oldText = this.el.innerText
const length = Math.max(oldText.length, newText.length)
const promise = new Promise((resolve) => this.resolve = resolve)
this.queue = []
for (let i = 0; i < length; i++) {
const from = oldText[i] || ''
const to = newText[i] || ''
const start = Math.floor(Math.random() * 40)
const end = start + Math.floor(Math.random() * 40)
this.queue.push({ from, to, start, end })
}
cancelAnimationFrame(this.frameRequest)
this.frame = 0
this.update()
return promise
}
update = () => {
let output = ''
let complete = 0
for (let i = 0, n = this.queue.length; i < n; i++) {
let { from, to, start, end, char } = this.queue[i]
if (this.frame >= end) {
complete++
output += to
} else if (this.frame >= start) {
if (!char || Math.random() < 0.28) {
char = this.randomChar()
this.queue[i].char = char
}
output += `<span class="span">${char}</span>`
} else {
output += from
}
}
this.el.innerHTML = output
if (complete === this.queue.length) {
this.resolve()
}
else {
this.frameRequest = requestAnimationFrame(this.update)
this.frame++
}
}
randomChar() {
return this.chars[Math.floor(Math.random() * this.chars.length)]
}
}
// ——————————————————————————————————————————————————
// Example
// ——————————————————————————————————————————————————
const phrases = {
'Coding' : 'none',
'With' : 'none',
'Muhammad': 'none',
'Coding With Muhammad' : 'fade'
}
let phraseValues = Object.keys(phrases);
const el = document.querySelector('.text')
const fx = new TextScramble(el, phraseValues.length)
let counter = 0
let animation = phraseValues[0];
let animate = (callback) => {
callback();
return function() {
document.querySelector(".text").animate([
// keyframes
{ opacity: '0' },
{ opacity: '1' }
], {
// timing options
duration: 3500
});
}
}
const next = () => {
fx.setText(phraseValues[counter]).then(() => {
if (counter < phraseValues.length-1)
setTimeout(next, 800)
else {
setTimeout(() => {next, animate(next, fx.update)()}, 800)
}
})
counter = (counter + 1) % phraseValues.length
}
next()
html, body {
font-family: 'Roboto Mono', monospace;
background: #212121;
height: 100%;
}
.container {
height: 100%;
width: 100%;
justify-content: center;
align-items: center;
display: flex;
}
.text {
font-weight: 100;
font-size: 28px;
color: #FAFAFA;
}
.dud {
color: #757575;
}
<div class="container">
<div class="text"></div>
</div>
I'm developping this mobile app and I'm usint this (https://github.com/krisrak/appframework-templates/blob/master/template-CarouselViewApp.html) as a carousel to change through content on a page. http://jsfiddle.net/nafis56/qCkqb/
So for this I need to mess around in HTML, CSS and Jquery. Unfortonetly I'm still very green at javascript so I need your help. I changed an ID to a Class because I need to call it more than once in the same page. In the original template I refeered to, it comes as an ID. So I did this to change it:
Changed matching code on html to call it as a Class.
<div class="panel" title="Desiree Charms" id="desiree_charms" style="overflow: hidden;"
data-appbuilder-object="page">
<div class="carousel">
<div class="carousel_page">
<h2>Desiree Charms</h2>
<p><img src="images/desiree_charms.jpg" style="width: 85%; height: 85%; display: block; margin-left: auto; margin-right: auto "
data-appbuilder-object="image" class="" title="">
</p>
</div>
<div class="carousel_page">
<h2>Page Two</h2>
<p>Text and images for Page Two goes here. Swipe to go to the
next page.</p>
</div>
</div>
<div class="carousel_dots"></div>
</div>
also this on the html.
<script>
$.ui.autoLaunch = false;
$.ui.animateHeaders = false;
$(document).ready(function(){
$.ui.launch();
});
$.ui.ready(function(){
carouselSetup();
});
function carouselSetup(){
// set size of carousel
$(".carousel").width($(".carousel").closest(".panel").width());
$(".carousel").height($(".carousel").closest(".panel").height()-25);
var options={
vertical:false, // page up/down
horizontal:true, // page left/right
pagingDiv:"carousel_dots", // div to hold the dots for paging
pagingCssName:"carousel_paging", //classname for the paging dots
pagingCssNameSelected: "carousel_paging_selected", //classname for the selected page dots
wrap:true //Creates a continuous carousel
}
var carousel = $(".carousel").carousel(options);
}
Changed # to . on Css.
.carousel {
overflow:hidden;
margin:0 -10px;
}
.carousel_page {
overflow: auto;
-webkit-scrolling:touch;
padding:0 10px;
}
.carousel_dots {
text-align: center;
margin-left: auto;
margin-right: auto;
clear: both;
position:relative;
top:0;
z-index:200;
}
.carousel_paging {
border-radius: 10px;
background: #ccc;
width: 10px;
height: 10px;
display:inline-block;
}
.carousel_paging_selected {
border-radius: 10px;
background: #000;
width: 10px;
height: 10px;
display:inline-block;
}
.carousel h2 {
text-align: center;
}
This is the jquery ( I didn't change anything)
/**
* af.web.carousel - a carousel library for App Framework apps
* #copyright 2011 - Intel
*
*/
(function($) {
var cache = [];
var objId=function(obj){
if(!obj.afmCarouselId) obj.afmCarouselId=$.uuid();
return obj.afmCarouselId;
}
$.fn.carousel = function(opts) {
var tmp, id;
for (var i = 0; i < this.length; i++) {
//cache system
id = objId(this[i]);
if(!cache[id]){
tmp = new carousel(this[i], opts);
cache[id] = tmp;
} else {
tmp = cache[id];
}
}
return this.length == 1 ? tmp : this;
};
var carousel = (function() {
var translateOpen =$.feat.cssTransformStart;
var translateClose = $.feat.cssTransformEnd;
var carousel = function(containerEl, opts) {
if (typeof containerEl === "string" || containerEl instanceof String) {
this.container = document.getElementById(containerEl);
} else {
this.container = containerEl;
}
if (!this.container) {
alert("Error finding container for carousel " + containerEl);
return;
}
if (this instanceof carousel) {
for (var j in opts) {
if (opts.hasOwnProperty(j)) {
this[j] = opts[j];
}
}
} else {
return new carousel(containerEl, opts);
}
var that = this;
af(this.container).bind('destroy', function(e){
var id = that.container.afmCarouselId;
//window event need to be cleaned up manually, remaining binds are automatically killed in the dom cleanup process
window.removeEventListener("orientationchange", that.orientationHandler, false);
if(cache[id]) delete cache[id];
e.stopPropagation();
});
this.pagingDiv = this.pagingDiv ? document.getElementById(this.pagingDiv) : null;
// initial setup
this.container.style.overflow = "hidden";
if (this.vertical) {
this.horizontal = false;
}
var el = document.createElement("div");
this.container.appendChild(el);
var $el=$(el);
var $container=$(this.container);
var data = Array.prototype.slice.call(this.container.childNodes);
while(data.length>0)
{
var myEl=data.splice(0,1);
myEl=$container.find(myEl);
if(myEl.get(0)==el)
continue;
$el.append(myEl.get(0));
}
if (this.horizontal) {
el.style.display = "block";
el.style['float']="left";
}
else {
el.style.display = "block";
}
this.el = el;
this.refreshItems();
var afEl = af(el);
afEl.bind('touchmove', function(e) {that.touchMove(e);});
afEl.bind('touchend', function(e) {that.touchEnd(e);});
afEl.bind('touchstart', function(e) {that.touchStart(e);});
this.orientationHandler = function() {that.onMoveIndex(that.carouselIndex,0);};
window.addEventListener("orientationchange", this.orientationHandler, false);
};
carousel.prototype = {
wrap:true,
startX: 0,
startY: 0,
dx: 0,
dy: 0,
glue: false,
myDivWidth: 0,
myDivHeight: 0,
cssMoveStart: 0,
childrenCount: 0,
carouselIndex: 0,
vertical: false,
horizontal: true,
el: null,
movingElement: false,
container: null,
pagingDiv: null,
pagingCssName: "carousel_paging",
pagingCssNameSelected: "carousel_paging_selected",
pagingFunction: null,
lockMove:false,
okToMove: false,
// handle the moving function
touchStart: function(e) {
this.okToMove = false;
this.myDivWidth = numOnly(this.container.clientWidth);
this.myDivHeight = numOnly(this.container.clientHeight);
this.lockMove=false;
if (e.touches[0].target && e.touches[0].target.type !== undefined) {
var tagname = e.touches[0].target.tagName.toLowerCase();
if (tagname === "select" || tagname === "input" || tagname === "button") // stuff we need to allow
{
return;
}
}
if (e.touches.length === 1) {
this.movingElement = true;
this.startY = e.touches[0].pageY;
this.startX = e.touches[0].pageX;
var cssMatrix=$.getCssMatrix(this.el);
if (this.vertical) {
try {
this.cssMoveStart = numOnly(cssMatrix.f);
} catch (ex1) {
this.cssMoveStart = 0;
}
} else {
try {
this.cssMoveStart = numOnly(cssMatrix.e);
} catch (ex1) {
this.cssMoveStart = 0;
}
}
}
},
touchMove: function(e) {
if(!this.movingElement)
return;
if (e.touches.length > 1) {
return this.touchEnd(e);
}
var rawDelta = {
x: e.touches[0].pageX - this.startX,
y: e.touches[0].pageY - this.startY
};
if (this.vertical) {
var movePos = { x: 0, y: 0 };
this.dy = e.touches[0].pageY - this.startY;
this.dy += this.cssMoveStart;
movePos.y = this.dy;
e.preventDefault();
//e.stopPropagation();
} else {
if ((!this.lockMove&&isHorizontalSwipe(rawDelta.x, rawDelta.y))||Math.abs(this.dx)>5) {
var movePos = {x: 0,y: 0};
this.dx = e.touches[0].pageX - this.startX;
this.dx += this.cssMoveStart;
e.preventDefault();
// e.stopPropagation();
movePos.x = this.dx;
}
else
return this.lockMove=true;
}
var totalMoved = this.vertical ? ((this.dy % this.myDivHeight) / this.myDivHeight * 100) * -1 : ((this.dx % this.myDivWidth) / this.myDivWidth * 100) * -1; // get a percentage of movement.
if (!this.okToMove) {
oldStateOkToMove= this.okToMove;
this.okToMove = this.glue ? Math.abs(totalMoved) > this.glue && Math.abs(totalMoved) < (100 - this.glue) : true;
if (this.okToMove && !oldStateOkToMove) {
$.trigger(this,"movestart",[this.el]);
}
}
if (this.okToMove && movePos)
this.moveCSS3(this.el, movePos);
},
touchEnd: function(e) {
if (!this.movingElement) {
return;
}
$.trigger(this,"movestop",[this.el]);
// e.preventDefault();
// e.stopPropagation();
var runFinal = false;
// try {
var cssMatrix=$.getCssMatrix(this.el);
var endPos = this.vertical ? numOnly(cssMatrix.f) : numOnly(cssMatrix.e);
if (1==2&&endPos > 0) {
this.moveCSS3(this.el, {
x: 0,
y: 0
}, "300");
} else {
var totalMoved = this.vertical ? ((this.dy % this.myDivHeight) / this.myDivHeight * 100) * -1 : ((this.dx % this.myDivWidth) / this.myDivWidth * 100) * -1; // get a percentage of movement.
// Only need
// to drag 3% to trigger an event
var currInd = this.carouselIndex;
if (endPos < this.cssMoveStart && totalMoved > 3) {
currInd++; // move right/down
} else if ((endPos > this.cssMoveStart && totalMoved < 97)) {
currInd--; // move left/up
}
var toMove=currInd;
//Checks for infinite - moves to placeholders
if(this.wrap){
if (currInd > (this.childrenCount - 1)) {
currInd = 0;
toMove=this.childrenCount;
}
if (currInd < 0) {
currInd = this.childrenCount-1;
toMove=-1;
}
}
else {
if(currInd<0)
currInd=0;
if(currInd>this.childrenCount-1)
currInd=this.childrenCount-1;
toMove=currInd;
}
var movePos = {
x: 0,
y: 0
};
if (this.vertical) {
movePos.y = (toMove * this.myDivHeight * -1);
}
else {
movePos.x = (toMove * this.myDivWidth * -1);
}
this.moveCSS3(this.el, movePos, "150");
if (this.pagingDiv && this.carouselIndex !== currInd) {
document.getElementById(this.container.id + "_" + this.carouselIndex).className = this.pagingCssName;
document.getElementById(this.container.id + "_" + currInd).className = this.pagingCssNameSelected;
}
if (this.carouselIndex != currInd)
runFinal = true;
this.carouselIndex = currInd;
//This is for the infinite ends - will move to the correct position after animation
if(this.wrap){
if(toMove!=currInd){
var that=this;
window.setTimeout(function(){
that.onMoveIndex(currInd,"1ms");
},155);
}
}
}
//} catch (e) {
// console.log(e);
// }
this.dx = 0;
this.movingElement = false;
this.startX = 0;
this.dy = 0;
this.startY = 0;
if (runFinal && this.pagingFunction && typeof this.pagingFunction == "function")
this.pagingFunction(this.carouselIndex);
},
onMoveIndex: function(newInd,transitionTime) {
this.myDivWidth = numOnly(this.container.clientWidth);
this.myDivHeight = numOnly(this.container.clientHeight);
var runFinal = false;
if(document.getElementById(this.container.id + "_" + this.carouselIndex))
document.getElementById(this.container.id + "_" + this.carouselIndex).className = this.pagingCssName;
var newTime = Math.abs(newInd - this.carouselIndex);
var ind = newInd;
if (ind < 0)
ind = 0;
if (ind > this.childrenCount - 1) {
ind = this.childrenCount - 1;
}
var movePos = {
x: 0,
y: 0
};
if (this.vertical) {
movePos.y = (ind * this.myDivHeight * -1);
}
else {
movePos.x = (ind * this.myDivWidth * -1);
}
var time =transitionTime?transitionTime: 50 + parseInt((newTime * 20));
this.moveCSS3(this.el, movePos, time);
if (this.carouselIndex != ind)
runFinal = true;
this.carouselIndex = ind;
if (this.pagingDiv) {
var tmpEl = document.getElementById(this.container.id + "_" + this.carouselIndex);
if(tmpEl) tmpEl.className = this.pagingCssNameSelected;
}
if (runFinal && this.pagingFunction && typeof this.pagingFunction == "function")
this.pagingFunction(currInd);
},
moveCSS3: function(el, distanceToMove, time, timingFunction) {
if (!time)
time = 0;
else
time = parseInt(time);
if (!timingFunction)
timingFunction = "linear";
el.style[$.feat.cssPrefix+"Transform"] = "translate" + translateOpen + distanceToMove.x + "px," + distanceToMove.y + "px" + translateClose;
el.style[$.feat.cssPrefix+"TransitionDuration"] = time + "ms";
el.style[$.feat.cssPrefix+"BackfaceVisibility"] = "hidden";
el.style[$.feat.cssPrefix+"TransitionTimingFunction"] = timingFunction;
},
addItem: function(el) {
if (el && el.nodeType) {
this.container.childNodes[0].appendChild(el);
this.refreshItems();
}
},
refreshItems: function() {
var childrenCounter = 0;
var that = this;
var el = this.el;
$(el).children().find(".prevBuffer").remove();
$(el).children().find(".nextBuffer").remove();
n = el.childNodes[0];
var widthParam;
var heightParam = "100%";
var elems = [];
for (; n; n = n.nextSibling) {
if (n.nodeType === 1) {
elems.push(n);
childrenCounter++;
}
}
//Let's put the buffers at the start/end
if(this.wrap){
var prep=$(elems[elems.length-1]).clone().get(0);
$(el).prepend(prep);
var tmp=$(elems[0]).clone().get(0);
$(el).append(tmp);
elems.push(tmp);
elems.unshift(prep);
tmp.style.position="absolute";
prep.style.position="absolute";
}
var param = (100 / childrenCounter) + "%";
this.childrenCount = childrenCounter;
widthParam = parseFloat(100 / childrenCounter) + "%";
for (var i = 0; i < elems.length; i++) {
if (this.horizontal) {
elems[i].style.width = widthParam;
elems[i].style.height = "100%";
elems[i].style['float']="left";
}
else {
elems[i].style.height = widthParam;
elems[i].style.width = "100%";
elems[i].style.display = "block";
}
}
//Clone the first and put it at the end
this.moveCSS3(el, {
x: 0,
y: 0
});
if (this.horizontal) {
el.style.width = Math.ceil((this.childrenCount) * 100) + "%";
el.style.height = "100%";
el.style['min-height'] = "100%"
if(this.wrap){
prep.style.left="-"+widthParam;
tmp.style.left="100%";
}
}
else {
el.style.width = "100%";
el.style.height = Math.ceil((this.childrenCount) * 100) + "%";
el.style['min-height'] = Math.ceil((this.childrenCount) * 100) + "%";
if(this.wrap){
prep.style.top="-"+widthParam;
tmp.style.top="100%";
}
}
// Create the paging dots
if (this.pagingDiv) {
this.pagingDiv.innerHTML = ""
for (i = 0; i < this.childrenCount; i++) {
var pagingEl = document.createElement("div");
pagingEl.id = this.container.id + "_" + i;
pagingEl.pageId = i;
if (i !== this.carouselIndex) {
pagingEl.className = this.pagingCssName;
}
else {
pagingEl.className = this.pagingCssNameSelected;
}
pagingEl.onclick = function() {
that.onMoveIndex(this.pageId);
};
var spacerEl = document.createElement("div");
spacerEl.style.width = "20px";
if(this.horizontal){
spacerEl.style.display = "inline-block";
spacerEl.innerHTML = " ";
}
else{
spacerEl.innerHTML=" ";
spacerEl.style.display="block";
}
this.pagingDiv.appendChild(pagingEl);
if (i + 1 < (this.childrenCount))
this.pagingDiv.appendChild(spacerEl);
pagingEl = null;
spacerEl = null;
}
if(this.horizontal){
this.pagingDiv.style.width = (this.childrenCount) * 50 + "px";
this.pagingDiv.style.height = "25px";
}
else {
this.pagingDiv.style.height = (this.childrenCount) * 50 + "px";
this.pagingDiv.style.width = "25px";
}
}
this.onMoveIndex(this.carouselIndex);
}
};
return carousel;
})();
function isHorizontalSwipe(xAxis, yAxis) {
var X = xAxis;
var Y = yAxis;
var Z = Math.round(Math.sqrt(Math.pow(X,2)+Math.pow(Y,2))); //the distance - rounded - in pixels
var r = Math.atan2(Y,X); //angle in radians
var swipeAngle = Math.round(r*180/Math.PI); //angle in degrees
if ( swipeAngle < 0 ) { swipeAngle = 360 - Math.abs(swipeAngle); } // for negative degree values
if (((swipeAngle <= 215) && (swipeAngle >= 155)) || ((swipeAngle <= 45) && (swipeAngle >= 0)) || ((swipeAngle <= 360) && (swipeAngle >= 315))) // horizontal angles with threshold
{return true; }
else {return false}
}
})(af);
Now, on the CSS file when I change .carousel_dots to #carousel_dots as it was originally. The carousel starts working. The problem is I need it as a class not an ID.
I'm pretty sure the problem is in the jquery, somewhere in there I need to set carousel_dots as a class and not an ID, but where?
Any help will be much apreciated, thanks.
jQuery is designed to trigger on HTML selectors, either elements, ID's or Class's. It's very common for it to trigger on ID's because, as you identified, they occur once and that isolates the action to that particular item.
I know that you changed the ID's to Class's because you want to use the CSS class multiple times. You can do this by using Class's. But, to maintain the jQuery logic, you should not change the ID's to Class's for that purpose. Use the ID's to synch with jQuery. Use Class's to control your CSS.
It's difficult to advise you regarding the case you displayed because you didn't identify the initial status and exactly how you changed it. If you can do that, we can be specific about what changes you should make. Good luck.
Is it possible to customize the fancybox HTML code?
I want to move out the next and previous buttons outside the .fancybox-outer
In order to move out the next and previous buttons of the .fancybox-outer container, you just need to add these CSS rules (in your own custom CSS file and AFTER you loaded the fancybox CSS file)
.fancybox-nav {
width: 60px;
}
.fancybox-nav span {
visibility: visible;
opacity: 0.5;
}
.fancybox-nav:hover span {
opacity: 1;
}
.fancybox-next {
right: -60px;
}
.fancybox-prev {
left: -60px;
}
You said you have looked around in the documentation but haven't found anything but the above is well documented in the fancyapps.com website here --> http://fancyapps.com/fancybox/#useful check No. 6, and the demo is in this fiddle
... but wonder if you will consider this as a correct answer.
Here is how I solved it. I did not know before that you could extend/replace methods in jquery. But this new method will (with some basic css) slide in from the right and out to the left.
It renders the buttons outside of the fancybox-outer element and it takes the width of the documen. It can probably be optimized a lot.
jQuery('ul a').fancybox({
margin: 0,
openMethod : 'afterZoomIn',
nextMethod : 'slideIn',
nextSpeed : 1000,
prevMethod : 'slideOut',
prevSpeed : 1000
});
(function ($, F) {
var getScalar = function(value, dim) {
var value_ = parseInt(value, 10);
if (dim && isPercentage(value)) {
value_ = F.getViewport()[ dim ] / 100 * value_;
}
return Math.ceil(value_);
},
getValue = function(value, dim) {
return getScalar(value, dim) + 'px';
};
F.transitions.afterZoomIn = function () {
var current = F.current;
if (!current) {
return;
}
F.isOpen = F.isOpened = true;
F.wrap.addClass('fancybox-opened').css('overflow', 'visible');
F.reposition();
// Assign a click event
if (current.closeClick || current.nextClick) {
F.inner.css('cursor', 'pointer').bind('click.fb', function(e) {
if (!$(e.target).is('a') && !$(e.target).parent().is('a')) {
F[ current.closeClick ? 'close' : 'next' ]();
}
});
}
// Create a close button
if (current.closeBtn) {
$(current.tpl.closeBtn).appendTo('.fancybox-overlay').bind('click.fb', F.close);
}
// Create navigation arrows
if (current.arrows && F.group.length > 1) {
if (current.loop || current.index > 0) {
$(current.tpl.prev).appendTo('.fancybox-overlay').bind('click.fb', F.prev);
}
if (current.loop || current.index < F.group.length - 1) {
$(current.tpl.next).appendTo('.fancybox-overlay').bind('click.fb', F.next);
}
}
F.trigger('afterShow');
// Stop the slideshow if this is the last item
if (!current.loop && current.index === current.group.length - 1) {
F.play( false );
} else if (F.opts.autoPlay && !F.player.isActive) {
F.opts.autoPlay = false;
F.play();
}
};
F.transitions.slideIn = function () {
var current = F.current,
effect = current.nextEffect,
startPos = current.pos,
endPos = { opacity : 1 },
direction = F.direction,
distance = $(document).width(),
field;
startPos.opacity = 0.1;
field = 'left';
if (direction === 'right') {
startPos[ field ] = getValue(getScalar(startPos[ field ]) - distance);
endPos[ field ] = '+=' + distance + 'px';
} else {
startPos[ field ] = getValue(getScalar(startPos[ field ]) + distance);
endPos[ field ] = '-=' + distance + 'px';
}
// Workaround for http://bugs.jquery.com/ticket/12273
if (effect === 'none') {
F._afterZoomIn();
} else {
F.wrap.css(startPos).animate(endPos, {
duration : current.nextSpeed,
easing : current.nextEasing,
complete : F._afterZoomIn
});
}
};
F.transitions.slideOut = function () {
var previous = F.previous,
effect = previous.prevEffect,
endPos = { opacity : 0 },
direction = F.direction,
distance = $(document).width();
if (effect === 'elastic') {
endPos[ 'left' ] = ( direction === 'left' ? '-' : '+' ) + '=' + distance + 'px';
}
previous.wrap.animate(endPos, {
duration : effect === 'none' ? 0 : previous.prevSpeed,
easing : previous.prevEasing,
complete : function () {
// $(this).trigger('onReset').remove();
previous.wrap.trigger('onReset').remove();
}
});
}
}(jQuery, jQuery.fancybox));