How to style slides on the edges in Swiper slider - javascript

I'm using Swiper slider plugin (https://swiperjs.com). And I need to add opacity 0.5 to slides on the edges of visible viewport. https://i.stack.imgur.com/A6nr5.png
I find out that I can select the right slide with this selector, and change it with media queries when quantity of visible slides change:
.swiper-slide-active + * + * + * {
opacity: 0.5;
}
But this trick will not work for the slide from the left side. I guess there is no only CSS solution and I have to use JS to detect visible slides?
const specialSlider = new Swiper('.special-slider', {
loop: true,
speed: 1000,
slidesPerView: 'auto',
spaceBetween: 30,
centeredSlides: true,
navigation: {
nextEl: '.special-slider__next',
prevEl: '.special-slider__prev',
},
watchOverflow: true,
grabCursor: true,
});

It is pretty easy, swiper does the heavy lifting for you. Just add this in your swiper settings:
// Deprecated
// watchSlidesVisibility: true
// 7.0.0 +
watchSlidesProgress: true
Now you can use the class swiper-slide-visible to style your visible slides.
For example:
.swiper-slide {
opacity: .25;
}
.swiper-slide-visible {
opacity: 1;
}
Keep in mind, it is easy to change the namespace for each class:
slideClass: 'myslider__slide',
slideVisibleClass: 'myslider__slide--visible'
Update
Example on Codepen
Update 2
Example (only 1 edge) on Codepen

Here is a solution that I find out:
const specialSlider = new Swiper('.special-slider', {
loop: true,
speed: 1000,
slidesPerView: 'auto',
spaceBetween: 0,
centeredSlides: true,
navigation: {
nextEl: '.special-slider__next',
prevEl: '.special-slider__prev',
},
watchOverflow: true,
grabCursor: true,
on: {
init: makeSlidesTransparent,
slideChangeTransitionStart: makeSlidesTransparent,
}
});
function makeSlidesTransparent() {
//Hide old slides
const oldSlides = d.getAll('.special-slider__item.js-visible');
for (let i = 0; i < oldSlides.length; i++) {
oldSlides[i].classList.remove('js-visible')
}
const width = window.innerWidth;
if (width >= 0 && width < 960) {
//Make visible new slides
const activeSlide = d.get('.special-slider__item.swiper-slide-active');
activeSlide.classList.add('js-visible');
}
if (width >= 960 && width < 1700) {
//Make visible new slides
const activeSlide = d.get('.special-slider__item.swiper-slide-active');
const prev1 = activeSlide.previousElementSibling;
const next1 = activeSlide.nextElementSibling;
prev1.classList.add('js-visible');
activeSlide.classList.add('js-visible');
next1.classList.add('js-visible');
}
if (width >= 1700) {
//Make visible new slides
const activeSlide = d.get('.special-slider__item.swiper-slide-active');
const prev1 = activeSlide.previousElementSibling;
const prev2 = prev1.previousElementSibling;
const next1 = activeSlide.nextElementSibling;
const next2 = next1.nextElementSibling;
prev1.classList.add('js-visible');
prev2.classList.add('js-visible');
activeSlide.classList.add('js-visible');
next1.classList.add('js-visible');
next2.classList.add('js-visible');
}
}
And styles:
.special-slider {
&__item {
padding-left: 15px;
padding-right: 15px;
width: 330px;
box-sizing: border-box;
height: auto;
opacity: 0.5;
transition: all $transition-style-slow;
&.js-visible{
opacity: 1;
}
.product-item {
background-color: rgba(218, 215, 205, 0.2);
}
}
}

Related

Div scales on scroll but how can I set a max-width? [anime,js]

I'm currently trying out anime.js and wanted to make a background transition.
const divAnimation = anime({
targets: '.background__circle',
scale: [0, 50],
easing: 'easeOutCirc',
autoplay: false,
opacity: 1,
});
const scrollPercent = () => {
const bodyST = document.body.scrollTop;
const docST = document.documentElement.scrollTop;
const docSH = document.documentElement.scrollHeight;
const docCH = document.documentElement.clientHeight;
return (docST + bodyST) / (docSH - docCH) * 100
}
window.onscroll = () => {
divAnimation.seek((scrollPercent() / 300) * divAnimation.duration);
};
.background__1 {
background-color: rgb( 56, 84, 58 );
height: 1000px;
}
.background__circle {
width: 50px;
height: 50px;
border-top-right-radius: 50%;
background-color: #3d6d41 ;
}
.background__2 {
background-color: #3d6d41 ;
height: 1000px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>
<div class="background__1">
</div>
<div class="background__circle"></div>
<div class="background__2"></div>
It should work like that. But my problem is that I don't want that you can scroll in x-direction. Is there a way how I can enable a max-width within the animation progress? Or like 100%?
What I tried was like overflow-x: hidden but that didn't work like it had to.

Set game scale ratio

I'm trying to fit the game to the screen, however I'm unable to scale the stage itself. With libraries like EaselJS from CreateJS I can simply do stage.scaleX = stage.scaleY = r.
In Phaser, I want to scale not only the game, but also together a HTML div (for user interface) that is outside Phaser. As you can see, the drawn rectangle is not scaled according to the current screen size, no matter what properties I change (game.scale.scaleMode, game.scale.displayScale etc.). Is there anything I can do?
const ProjectSettings = {
backgroundColor: 0x333333,
resolution: [100, 100],
};
const SceneContainers = {
sceneContent: null,
sceneCanvas: null,
phaserGame: null,
sceneUIDiv: null,
init() {
SceneContainers.sceneContent = document.getElementById('content');
SceneContainers.phaserGame = new Phaser.Game({
width: ProjectSettings.resolution[0],
height: ProjectSettings.resolution[1],
type: Phaser.AUTO,
parent: SceneContainers.sceneContent,
backgroundColor: ProjectSettings.backgroundColor,
scene: [Preloader],
});
SceneContainers.sceneCanvas = SceneContainers.phaserGame.canvas;
SceneContainers.sceneCanvas.classList.add('scene-canvas');
SceneContainers.sceneUIDiv = document.createElement('div');
SceneContainers.sceneUIDiv.id = 'scene-ui';
SceneContainers.sceneContent.appendChild(SceneContainers.sceneUIDiv);
},
};
const SceneScaler = {
init() {
SceneContainers.phaserGame.scale.scaleMode = Phaser.Scale.ScaleModes.RESIZE;
SceneScaler.fitToScreen();
window.addEventListener('resize', e => {
SceneScaler.fitToScreen();
});
},
fitToScreen() {
const [contentW, contentH] = ProjectSettings.resolution;
const [windowW, windowH] = [innerWidth, innerHeight];
const ratio = contentW / contentH;
const windowRatio = windowW / windowH;
let scale = windowW / contentW;
if (windowRatio > ratio) {
scale = windowH / contentH;
}
//SceneContainers.sceneCanvas.width = contentW * scale;
//SceneContainers.sceneCanvas.height = contentH * scale;
SceneContainers.phaserGame.scale.resize(contentW * scale, contentH * scale);
SceneContainers.sceneUIDiv.style.transform = `scale(${scale})`;
SceneContainers.sceneContent.style.width = `${contentW * scale}px`;
SceneContainers.sceneContent.style.height = `${contentH * scale}px`;
SceneContainers.sceneUIDiv.style.width = `${contentW}px`;
SceneContainers.sceneUIDiv.style.height = `${contentH}px`;
SceneContainers.sceneContent.style.left =
SceneContainers.sceneCanvas.style.left =
SceneContainers.sceneUIDiv.style.left = `${windowW / 2 - (contentW * scale) / 2}px`;
SceneContainers.sceneContent.style.top =
SceneContainers.sceneCanvas.style.top =
SceneContainers.sceneUIDiv.style.top = `${windowH / 2 - (contentH * scale) / 2}px`;
//SceneContainers.phaserGame.scale.displayScale = new Phaser.Math.Vector2(scale, scale);
},
};
class Scene extends Phaser.Scene {
constructor(id) {
super(id);
}
init() {
this.events.on('shutdown', () => {
SceneContainers.sceneUIDiv.innerHTML = '';
});
}
}
class Preloader extends Scene {
constructor() {
super('preloader');
}
preload() {
}
create() {
this.add.rectangle(50, 50, 50, 50, 0xff6666);
}
}
class EntryPoint {
constructor() {
this.init();
}
init() {
SceneContainers.init();
SceneScaler.init();
}
}
new EntryPoint;
html, body {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
}
html, body {
background: #333333;
}
#content {
position: absolute;
display: inline-block;
}
.scene-canvas {
position: absolute;
}
#scene-ui {
display: inline-block;
position: absolute;
transform-origin: left top;
}
<script src="https://github.com/photonstorm/phaser/releases/download/v3.55.2/phaser.min.js"></script>
<div id="content"></div>
Also, for some reason my snippet is giving undefined for canvas.classList, so I appreciate if someone could fix that. This classList error is not happening with my project.
If you are only looking for automatic scaling, you could use the config parameter scale.mode (of the Phaser Game Object) and set it to Phaser.Scale.FIT, then everything should be scaled.
Here a very simplified demo:
If you resize the window (when you open the snipplet fullsize and change the height), you should see "the scaling"
var Preloader = {
create() {
this.add.rectangle(50, 50, 50, 50, 0xff6666);
}
};
new Phaser.Game({
width:300,
height:300,
scale: {
mode: Phaser.Scale.FIT,
},
type: Phaser.AUTO,
scene: [Preloader],
});
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.min.js"></script>

Create checkbox mecanism with Fabric JS

How can you create a checkbox like component with Fabric JS? More like to click on the image, and to set the opacity to 0. If you click again, to set the opacity to 1.
Here is my code:
For the checkbox image:
fabric.Image.fromURL('https://image.flaticon.com/icons/svg/33/33281.svg', (image) => {
image.scale(0.35);
image.set({
left: 152,
top: 120,
hoverCursor: 'default',
selectable: true,
opacity: 0.5,
hasControls: false,
lockMovementX: true,
lockMovementY: true
})
if(image.onselect === true ) {
image.set().opacity = 0;
}
canvas.add(image);
});
The box where the image is put:
function addBox(left, top, width, height) {
const o = new fabric.Rect({
left: left,
top: top,
width: 30,
height: 30,
fill: boxFill,
strokeWidth: 2,
originX: 'left',
originY: 'top',
centeredRotation: true,
snapAngle: 45,
selectable: true,
type: 'box',
id: generateId()
})
if(image.onselect === true ) {
image.set().opacity = 0;
}
canvas.add(o)
canvas.getObjects().map(o => {
o.hasControls = false
o.lockMovementX = true
o.lockMovementY = true
o.borderColor = '#38A62E'
o.borderScaleFactor = 2.5
})
canvas.selection = false
canvas.hoverCursor = 'pointer'
canvas.discardActiveObject()
canvas.renderAll()
return o
}
How can I resolve this issue? Is there a way to make the image appear and dissapear when you click on it ( using opacity or something similarly) ?
Hope this helps you and many who want to add Event on objects.
var canvas = new fabric.Canvas("canvas");
function drawCheckbox(left,right, width, height){
var imgClass = new fabric.Image.fromURL('https://image.flaticon.com/icons/svg/33/33281.svg',function(img){
img.width = width;
img.height = height;
img.left = left;
img.top = right;
img.hasControls = false
img.on('mousedown', function(e) {
if(e.target.opacity <= 0.5){
e.target.opacity = 1;
}else{
e.target.opacity = 0.4;
}
canvas.renderAll();
});
canvas.add(img);
canvas.renderAll();
})
}
drawCheckbox(0,0, 100,100)
drawCheckbox(100,100, 100,100)
drawCheckbox(200,200, 100,100)
body {
background-color:silver;
}
canvas {
border:1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.3/fabric.min.js"> </script>
<canvas id="canvas" width=300 height=300></canvas><br>

When looping through animations, only the last loop runs

This is a follow up from my previous question.
I have a progressbar.js circle that animates on scroll. If there is just one circle it works as expected.
Now I want to create many of these animated circles by looping through an object with different key-values pairs.
For example:
var divsValues = {
'total-score-circle': 0.75,
'general-score-circle': 0.80,
'speed-score-circle': 0.85,
'privacy-score-circle': 0.90,
};
For each key-value pair, the key is a div ID and the value is number that tells the animation how far to go.
Below is the code where I try to implement my loop, but the problem is that only the last circle is animated on scroll. All the circles appear in their "pre-animation" state, but only the last circle actually becomes animated when you scroll to the bottom.
I need each circle to animate once it is in the viewport.
//Loop through my divs and create animated circle for each one
function makeCircles() {
var divsValues = {
'total-score-circle': 0.75,
'general-score-circle': 0.80,
'speed-score-circle': 0.85,
'privacy-score-circle': 0.90,
};
for (var i in divsValues) {
if (divsValues.hasOwnProperty(i)) {
bgCircles(i, divsValues[i]);
}
}
}
makeCircles();
// Check if element is scrolled into view
function isScrolledIntoView(elem) {
var docViewTop = jQuery(window).scrollTop();
var docViewBottom = docViewTop + jQuery(window).height();
var elemTop = jQuery(elem).offset().top;
var elemBottom = elemTop + jQuery(elem).height();
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}
//Circle design and animation
function bgCircles(divid, countvalue) {
// Design the circle using progressbar.js
bar = new ProgressBar.Circle(document.getElementById(divid), {
color: '#ddd',
// This has to be the same size as the maximum width to
// prevent clipping
strokeWidth: 4,
trailWidth: 4,
easing: 'easeInOut',
duration: 1400,
text: {
autoStyleContainer: false
},
from: {
color: '#ddd',
width: 4
},
to: {
color: '#888',
width: 4
},
// Set default step function for all animate calls
step: function(state, circle) {
circle.path.setAttribute('stroke', state.color);
circle.path.setAttribute('stroke-width', state.width);
var value = Math.round(circle.value() * 100);
if (value === 0) {
circle.setText('');
} else {
circle.setText(value + '%');
}
}
});
bar.text.style.fontFamily = '"Montserrat", sans-serif';
bar.text.style.fontSize = '1.7rem';
bar.trail.setAttribute('stroke-linecap', 'round');
bar.path.setAttribute('stroke-linecap', 'round');
//Animate the circle when scrolled into view
window.onscroll = function() {
if (isScrolledIntoView(jQuery('#' + divid))) bar.animate(countvalue);
else bar.animate(0); // or bar.set(0)
}
}
#total-score-circle,
#general-score-circle,
#speed-score-circle,
#privacy-score-circle {
margin: 0.8em auto;
width: 100px;
height: 100px;
position: relative;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/progressbar.js/1.0.1/progressbar.min.js"></script>
<div id="total-score-circle"></div>
<div id="general-score-circle"></div>
<div id="speed-score-circle"></div>
<div id="privacy-score-circle"></div>
While researching this problem I learned that JavaScript will only output the last value of a loop, which I thought could be the cause of my problem.
So I tried to replace the for loop with these solutions...
Solution 1: Same problem as before, only the last loop animates on scroll.
for (var i in divsValues) {
(function(){
var ii = i;
if (divsValues.hasOwnProperty(ii)) {
bgCircles(ii, divsValues[ii]);
}
})();
}
Solution 2: Again, same problem as before, only the last loop animates on scroll.
for (var i in divsValues) {
let ii = i;
if (divsValues.hasOwnProperty(ii)) {
bgCircles(ii, divsValues[ii]);
}
}
Solution 3: Again, same problem as before, only the last loop animates on scroll.
for (var i in divsValues) {
try{throw i}
catch(ii) {
if (divsValues.hasOwnProperty(ii)) {
bgCircles(ii, divsValues[ii]);
}
}
}
So now I'm thinking maybe the problem is not the loop, but something I can't see or figure out.
You were quite close.
Here are the fixes:
In the function bgCircles(...), use var to declare the bar in that function's scope:
var bar = new ProgressBar.Circle(document.getElementById(divid), {
When you set the animate scrolled into view checker event, you assign a new function over-and-over to window.onscroll. Since you are using jQuery, consider jQuery's .scroll event handler and use it like this:
$(window).scroll(function () {
if (isScrolledIntoView(jQuery('#' + divid))) bar.animate(countvalue);
else bar.animate(0); // or bar.set(0)
});
The solution in whole:
//Loop through my divs and create animated circle for each one
function makeCircles() {
var divsValues = {
'total-score-circle': 0.75,
'general-score-circle': 0.80,
'speed-score-circle': 0.85,
'privacy-score-circle': 0.90,
};
for (var i in divsValues) {
if (divsValues.hasOwnProperty(i)) {
bgCircles(i, divsValues[i]);
}
}
}
makeCircles();
// Check if element is scrolled into view
function isScrolledIntoView(elem) {
var docViewTop = jQuery(window).scrollTop();
var docViewBottom = docViewTop + jQuery(window).height();
var elemTop = jQuery(elem).offset().top;
var elemBottom = elemTop + jQuery(elem).height();
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}
//Circle design and animation
function bgCircles(divid, countvalue) {
// Design the circle using progressbar.js
var bar = new ProgressBar.Circle(document.getElementById(divid), {
color: '#ddd',
// This has to be the same size as the maximum width to
// prevent clipping
strokeWidth: 4,
trailWidth: 4,
easing: 'easeInOut',
duration: 1400,
text: {
autoStyleContainer: false
},
from: {
color: '#ddd',
width: 4
},
to: {
color: '#888',
width: 4
},
// Set default step function for all animate calls
step: function(state, circle) {
circle.path.setAttribute('stroke', state.color);
circle.path.setAttribute('stroke-width', state.width);
var value = Math.round(circle.value() * 100);
if (value === 0) {
circle.setText('');
} else {
circle.setText(value + '%');
}
}
});
bar.text.style.fontFamily = '"Montserrat", sans-serif';
bar.text.style.fontSize = '1.7rem';
bar.trail.setAttribute('stroke-linecap', 'round');
bar.path.setAttribute('stroke-linecap', 'round');
//Animate the circle when scrolled into view
$(window).scroll(function () {
if (isScrolledIntoView(jQuery('#' + divid))) bar.animate(countvalue);
else bar.animate(0); // or bar.set(0)
});
}
#total-score-circle,
#general-score-circle,
#speed-score-circle,
#privacy-score-circle {
margin: 0.8em auto;
width: 100px;
height: 100px;
position: relative;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/progressbar.js/1.0.1/progressbar.min.js"></script>
<div id="total-score-circle"></div>
<div id="general-score-circle"></div>
<div id="speed-score-circle"></div>
<div id="privacy-score-circle"></div>
Note:
Since I didn't edit any of your circle animation/circle visibility checking functions, I assume you intended the current state of your animate-when-scrolled-and-in-view functionality the way, that it is right now. In this current state, your script does/has the following side-effects:
If you don't scroll the page, not at all, your circles won't start to animate, even, when they are visible. Solution: encapsulate the visibility checker lines to a separate function and run, when creating the circles.
If you scroll through a circle, its animation with the percent will going to go to its default state, which is 0%. Solution: change the visibility checker function, when the particular element is not visible because of overscroll, return that state as visible too. This way your circles will stay at 100%, even when you scroll over them.
Regarding performance and best practices:
When using jQuery, make sure to call jQuery(...) or its shorthand $(...) as few times as possible. Use variables to store elements, properties, and data.
It's better to separate longer/larger, monolithic functions into smaller functions with a more narrow, but also more clear scope of functionality.
When using event listeners, make sure to run as few of them as possible. Structure your HTML and your JavaScript code to have clear and performant ways to access and modify your crucial elements, properties, and data.
The loop you have will run so fast that the browser engine wont be able to render the changes, I would suggest either you use setInterval() method or continuous setTimeout() method which will add some delay to your code so that the browser can render the changes you are making.
For your special case I would suggest:
var i = 0;
var tobecleared = setInterval(timer,1000);
function timer(){
var p = get_ith_key_from_divsvalues(i);//implement this method
console.log(p);
bgCircles(p, divsValues[p]);
i++;
if(i == Object.keys(divsValues).length)
clearInterval(tobecleared);
}
function get_ith_key_from_divsvalues(i){
var j = -1;
for(var property in divsValues){
j++;
if(j==i)
return property;
}
}
Note : window.onscroll is being overwritten in each call that is why only the last circle responds.
There are two fixes you need to apply.
Currently bar is the global variable, so it's always the same, to fix it declare it with var.
Use window.addEventListener to attach scroll event to window, by setting handler with window.onscroll you constantly override event handler and usage of addEventListener allow you attach more than one event handler.
//Loop through my divs and create animated circle for each one
$( document ).ready(function(){
function makeCircles() {
var divsValues = {
'total-score-circle': 0.75,
'general-score-circle': 0.80,
'speed-score-circle': 0.85,
'privacy-score-circle': 0.90,
};
for (var i in divsValues) {
if (divsValues.hasOwnProperty(i)) {
bgCircles(i, divsValues[i]);
}
}
}
makeCircles();
// Check if element is scrolled into view
function isScrolledIntoView(elem) {
var docViewTop = jQuery(window).scrollTop();
var docViewBottom = docViewTop + jQuery(window).height();
var elemTop = jQuery(elem).offset().top;
var elemBottom = elemTop + jQuery(elem).height();
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}
//Circle design and animation
function bgCircles(divid, countvalue) {
// Design the circle using progressbar.js
var bar = new ProgressBar.Circle(document.getElementById(divid), {
color: '#ddd',
// This has to be the same size as the maximum width to
// prevent clipping
strokeWidth: 4,
trailWidth: 4,
easing: 'easeInOut',
duration: 1400,
text: {
autoStyleContainer: false
},
from: {
color: '#ddd',
width: 4
},
to: {
color: '#888',
width: 4
},
// Set default step function for all animate calls
step: function(state, circle) {
circle.path.setAttribute('stroke', state.color);
circle.path.setAttribute('stroke-width', state.width);
var value = Math.round(circle.value() * 100);
if (value === 0) {
circle.setText('');
} else {
circle.setText(value + '%');
}
}
});
bar.text.style.fontFamily = '"Montserrat", sans-serif';
bar.text.style.fontSize = '1.7rem';
bar.trail.setAttribute('stroke-linecap', 'round');
bar.path.setAttribute('stroke-linecap', 'round');
//Animate the circle when scrolled into view
window.addEventListener('scroll', function() {
if (isScrolledIntoView(jQuery('#' + divid))) bar.animate(countvalue);
else bar.animate(0); // or bar.set(0)
})
}
})
#total-score-circle,
#general-score-circle,
#speed-score-circle,
#privacy-score-circle {
margin: 0.8em auto;
width: 100px;
height: 100px;
position: relative;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/progressbar.js/1.0.1/progressbar.min.js"></script>
<div id="total-score-circle"></div>
<div id="general-score-circle"></div>
<div id="speed-score-circle"></div>
<div id="privacy-score-circle"></div>

Greensock fading in and out on background image change

I have never used GreenSock before. The background image changes fine, it switches and scales in and out however the issues I am facing are as follows:
The first background image on the sprite to show does not scale in and out but all the others do, how can I fix this?
It seems to change the background then scale in and out. So there is a small delay between the changing of the background image and the start of scale animation. Is there anyway to tighten this up so it scales as its changed to make it a more smoother transition?
JavaScript:
// Avatar animations
var avatarInterval;
var fadePulse = true; // true: will fade avatar images and pulse in and out once changed
// false: will slide the avatars in and out
var avatarCount = 11; // set the amount of avatars in the sprite image
var avatarSpeed = 1000; // set the avatar transition speed
var avatarHeight = 250; // set the height of a single avatar image
var avatarTotalHeight = 2750; // set the total height of the avatar sprite image
function startAvatarAnimation() {
var i = 0;
$(".avatars").show();
// Loop through avatar background images on sprite
avatarInterval = setInterval(function(){
i++;
if(i > avatarCount){
i = 0;
}
// Let's change the background
$(".avatars").css({'background-position' : '0 -' + (i*avatarHeight) + 'px' });
// avatar fading / pulse effect
if (fadePulse == true) {
// Now some scaling effects!
TweenMax.to(avatars, 0.1, {
css: {
// 'background-position': '0 -' + (i*avatarHeight) + 'px',
scaleX: 1.1,
scaleY: 1.1,
transformOrigin: "center center"
},
onComplete: scaleOut,
onCompleteParams: [avatars],
delay: 0.1,
ease: Power3.easeInOut
});
// Bring the scale back to normal
function scaleOut(el) {
TweenMax.to(el, 0.1, {
css: {
scaleX: 1.0,
scaleY: 1.0,
transformOrigin: "center center",
autoAlpha: 1,
},
ease: Power2.easeOut
});
}
} else {
// avatar sliding effect
}
}, avatarSpeed);
return false;
}
Take a look at this result.
Snippet:
var avatarCount = 6;
var avatarHeight = 250;
var avatarTotalHeight = 1500;
var avatars = $(".avatars");
var animDuration = 0.1;
var i = 0;
var timeline = new TimelineMax({ paused: true, repeat: -1 });
timeline.to(avatars, animDuration, {
scaleX: 1.1,
scaleY: 1.1,
ease: Power3.easeIn,
onComplete: onCompleteScaleIn
});
timeline.to(avatars, animDuration, {
scaleX: 1.0,
scaleY: 1.0,
ease: Power3.easeOut
});
function onCompleteScaleIn() {
i++;
i = i >= avatarCount ? 0 : i;
TweenMax.set(avatars, {
backgroundPosition: '0 -' + (i * avatarHeight) + 'px'
});
}
timeline.play();
#container {} #container,
.section {
overflow: hidden;
position: relative;
}
.section {
position: absolute;
}
#container .logo_o2 {
bottom: 10px;
right: 20px;
}
.section {
position: relative;
height: 250px;
width: 300px;
display: block;
}
.section .abs {
position: absolute;
}
.section h1,
.section h2,
.section h3,
.section h4 {
font-size: 21px;
width: 100%;
text-align: center;
letter-spacing: 0;
}
.section1,
.section2,
.section3,
.section4,
.section5,
.section6 {} .avatars {
background-image: url(http://s1.postimg.org/dwt9yu9b3/test_bg_sprite.png);
background-repeat: no-repeat;
background-size: cover;
display: block;
height: 250px;
width: 300px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js"></script>
<div class="section section3">
<div class="abs clouds"></div>
<div id="avatars" class="abs avatars"></div>
</div>
Details:
First off, this result could have been achieved in a number of ways, more efficiently. Even within TweenMax there could have been a number of possible solutions. So, this attempt is in no way supposed to be the best.
Because you are already using GSAP; I have used TimelineMax, TweenMax's powerful cousin that makes sequencing of animations very easy.
So we have a timeline variable which carries an instance of TimelineMax object with default settings of: 1. initially paused and 2. indeterminate loops.
We then populate this timeline by using the method .to() which basically will start animation from wherever the object currently is. There are a plethora of methods and properties available for the GSAP platform, you should explore.
On the first line of .to() call, we have an onComplete callback pointing to a function.
This callback adjusts the backgroundPosition as per the current iteration.
Finally, there is another .to() call which does the same i.e. start the animation from whatever attributes avatars object currently possesses (in our case, scaleX & scaleY would be at 1.1 because of the first .to() call).
Note: by default, any new .to() (or .from() or .fromTo()) call is appended at the end of a timeline. Read more about the position parameter here.
Let me know if you have any questions.
Update: Here is another version using TweenMax only. Much leaner I guess.

Categories

Resources