Trouble with adding multiple pins and animating background position in Scrollmagic? - gsap

I have added a TimeLineMax to a scene that I am working on. The functionality is working great but I am having trouble with a few details.
I would like my scene to pin like this site http://www.google.com/inbox/#bundles . By this I want multiple pins within one scene so that a user can't scroll through my animations without viewing them.
Here is a demo site of my work so far : https://so-staging.herokuapp.com/users/sign_in#publisher-demo-container
You can see my progress if you scroll down. Three steps will pop up and then animate away. I also have adjusted the background position of #publisher-demo-steps based on scroll.
However this isn't the desired goal. I would like this:
1. Pin #publisher-demo
2. Fire step 1 animated background-position on scroll.
3. Fire step 2
4. Fire step 3
I would like each step to be pinned so that a user can't go to the next step until the animation is complete.
I know this is confusing and I have been staring at it way too long. Thanks for the help. Here is my scrollmagic and GSAP code.
var controller = new ScrollMagic();
var tween = new TimelineMax()
.add(TweenMax.to("#publisher-demo-steps", 0.5, {backgroundPosition : "50% 23%"}))
.add(TweenMax.to(".blue-circle", 1, {display: "block"}))
.add(TweenMax.to(".blue-circle", 1, {className: "+=animated zoomOut", display: "none", delay:3}))
.add(TweenMax.to("#publisher-demo-steps", 0.5, {backgroundPosition : "22% 52%"}))
.add(TweenMax.to(".red-circle", 1, {display: "block"}))
.add(TweenMax.to(".red-circle", 1, {className: "+=animated zoomOut", display: "none", delay:3}))
.add(TweenMax.to("#publisher-demo-steps", 0.5, {backgroundPosition : "76% 50%"}))
.add(TweenMax.to(".green-circle", 1, {display: "block"}))
.add(TweenMax.to(".green-circle", 1, {className: "+=animated zoomOut", display: "none", delay:3}));
var scene = new ScrollScene({triggerElement: "#publisher-demo", duration: 4000, triggerHook: -100})
.setPin("#publisher-demo")
.setTween(tween)
.addTo(controller);

If I understand you correctly you would like to trigger the animations to play unbound from scroll progress.
The way you do this is by not linking the scene that does the pin.
As soon as a scene has a duration it will link animation progress to scroll progress.
Then you just add a scene for each animation trigger point.
i.e. like this:
new ScrollScene({triggerElement: "#trigger-element", duration: 4000, triggerHook: 0})
.setPin("#publisher-demo")
.addTo(controller);
new ScrollScene({triggerElement: "#trigger-element", triggerHook: 0})
.setTween(new TimelineMax()
.to("#publisher-demo-steps", 0.5, {backgroundPosition : "50% 23%"})
.to(".blue-circle", 1, {display: "block"})
)
.addTo(controller);
new ScrollScene({triggerElement: "#trigger-element", triggerHook: 0, offset: 300)
.setTween(TweenMax.to(".blue-circle", 1, {className: "+=animated zoomOut", display: "none", delay:3}))
.addTo(controller);
General notes:
As you see I used a trigger element that is different from the pinned element. It should be positioned absolute and located at the same position as the pinned element. the reason I do this is, because the pinned element moves and would supply a wrong start position for the other scenes.
A triggerHook of -100 doesn't make any sense. The value can by definition only be between 0 and 1.
instead of TimelineMax().add(TweenMax.to()) you can use the shorthand TimelineMax().to() (see http://greensock.com/docs/#/HTML5/GSAP/TimelineMax/to/)
Note, that ScrollMagic 2 has been released for a while now. The syntax is very similar so you should consider upgrading.

Related

GSAP and ScrollMagic: Padding top and pin spacer

I am using GSAP v3 with ScrollMagic v2.0.7.
The problem I face is that after the animations are finished and I scroll up (reverse: false), it correctly registers that I don't want to execute the animations again on reverse, but it creates a padding-top equal to the duration of the scene:
const controller = new ScrollMagic.Controller();
const scene = new ScrollMagic.Scene({
triggerElement: "#responsive-divider",
duration: "100%",
triggerHook: 0,
reverse: false
})
.setTween(action)
.setPin("#responsive-divider")
.addTo(controller);
In this case, the height of the element with the id of "responsive-divider" is 311px, so the class "scrollmagic-pin-spacer" gets a padding-top: 311px;
If I inspect element and remove padding-top then everything is OK.
Why is this happening? Is there a way to prevent this?
PS1: if I do not disable "reverse" then it works just fine. But in this case I don't want to get the reverse animation.
PS2: I found a way around this but I don't know if its a hack or the solution. On my timeline I used the "onComplete: removePadding", and I did the following:
function removePadding() {
document.querySelector(".scrollmagic-pin-spacer").style.paddingTop = null;
}
Feels a little bit hacky to me.
Thanks in advance!
Adding triggerHook: 0 resolved the problem for me!

Vertically scrolling graph with fixed size nodes with Cytoscape.js?

I'm using Cytoscape to generate a simple flow/state diagram and I'm able to generate the graph, but as the graph grows, it just keeps zooming out so the nodes become really small. Is there a way to have Cytoscape to just keep growing in height instead of shrinking the graph and having to zoom in? I would rather have the nodes stay a known size (i.e. 100px X 100px) and as the graph grows and have it grow vertically so the user just has to scroll down the page to see the rest of the graph. Right now, the viewport is restricted to the height of the page when the page is first rendered. Let me know if there is a way to achieve a vertically scrolling graph with fixed size nodes. Thanks!
Based on the suggestions of maxkfranz and gcpdev, I came up with the following solution that seems to work pretty well.
Cytoscope Init:
cy = cytoscape({
container: document.getElementById('cy'),
style: cytoscape.stylesheet()
.selector('node')
.css({
'shape': 'roundrectangle',
'height': 80,
'width': 150,
'background-fit': 'cover',
'background-color': '#F5F5F5',
'border-color': '#F5F5F5',
'border-width': 3,
'border-opacity': 0.5,
'text-valign': 'center',
'content': 'data(name)',
})
.selector('edge')
.css({
'width': 6,
'target-arrow-shape': 'triangle',
'line-color': '#0088cc',
'target-arrow-color': '#0088cc'
}),
elements: data,
zoomingEnabled: false,
layout: {
name: 'breadthfirst',
directed: true,
padding: 10
}
}); // cy init
After we have initialized the diagram, we have to set the size of our container div to be at least as high as the bounds of the graph. We also need to reset the size anytime someone resizes the window.
cy.on('ready', function () {
updateBounds();
});
//if they resize the window, resize the diagram
$(window).resize(function () {
updateBounds();
});
var updateBounds = function () {
var bounds = cy.elements().boundingBox();
$('#cyContainer').css('height', bounds.h + 300);
cy.center();
cy.resize();
//fix the Edgehandles
$('#cy').cytoscapeEdgehandles('resize');
};
I am also calling updateBounds() any time the user add a node to the graph. This gives me a graph that is full size and grows vertically. I can scroll down the page just fine as well!
(1) Layouts usually fit to the graph. Set layoutOptions.fit: false to override this default behaviour (at least for included layouts).
(2) The use of (1) means that running the layout will leave the graph viewport in the reset state (i.e. default zoom of 1 at origin position { x: 0, y: 0 }). If you want the viewport maintained at zoom: 1 but with an altered pan position, you can use cy.pan() with some simple calculations with cy.elements().boundingBox(). You may also find cy.center() useful -- though perhaps only horizontally in your case.
(3) The use of (2) means that your graph viewport (i.e. canvas) will be the same size, but the user will be able to pan down to see the remainder of the graph. If you prefer scrolling over panning, you will need to implement your own mechanism for this. You can make clever combination of cy.elements().boundingBox() and jQuery('#cy-div').css(), for example, to adjust the cy div to the size of the graph. You may want to turn off user panning and zooming (and autolock nodes etc.), if the graph is not interactive.
Well, I think you could set the zoom amount to fixed and disable zoom in/out, and use some strategy to dynamically change your div/page's height.
This answer or this one should help you.

Flexslider - Navigation "one-by-one" - one click on arrow / one swipe / one keypress = movement of only one image

I'm using Flexslider for a project of gallery and I want to modify the navigation system.
On keypress/swipe/click on arrows, four images displayed disappear and are replaced by four new.
Is it possible to modify the behavior of the navigation to move images one by one ?
Thank you very much for your help !
Z.
You may want to use property move, which is defined as
//{NEW} Integer: Number of carousel items that should move on
animation. If 0, slider will move all visible items.
So, your code will look like this
$(window).load(function() {
$('.slidewidget1').flexslider({
animation: "slide",
animationLoop: true,
itemWidth: 210,
controlNav: false,
itemMargin: 0,
slideshow: false,
move: 1,
minItems = 4,
maxItems = 4
});
});
plus, of course, your customization of width, etc.
Documentation

KineticJS doesn't update object's position at initial onResize call

This is an experiment with KineticJS and its goal is to simply keep an objected centered in the screen, as the window gets resized.
It works fine except that it doesn't center the object (a circle) at the initial resize event handler call. As I start resizing - and keep doing it - the circle gets centered. But initially the circle starts at the top left corner of the screen (0,0).
$(document).ready( function(){
$(window).resize(onResize);
var stage = new Kinetic.Stage({
container: 'container',
width: $(container).width(),
height: $(container).height()
});
var layer = new Kinetic.Layer();
var circle = new Kinetic.Circle({ radius: 70, fill: 'red' });
layer.add(circle);
stage.add(layer);
function onResize(){
$(container).css('height', window.innerHeight - 20);
stage.setWidth($(container).width());
stage.setHeight($(container).height());
updatePosition();
}
function updatePosition(){
circle.setPosition(stage.getWidth() / 2, stage.getHeight() / 2);
}
// initial call
onResize();
});
Any clue on why that happens? Thanks
http://jsfiddle.net/ME2cX/2
Yeah, you are missing a call to draw the stage after the onResize function is called.
Your order of events is to add things to the stage, then place the circle in the center, but the stage (or layer) needs to be drawn again to account for the new position of the circle.
In the jsfiddle, I placed 3 draw functions, I recommend you choose one of the
layer.draw()
functions rather than the
stage.draw();

Flexslider carousel show two images when width is 768px

Problem
I use the flexslider carousel to a number of images to show. What I want now is, when the browser has a certain width drop a break, which for example is incidental to 768px 2 images are shown. Currently you see an image at a certain width but half and wants to these points with javascript / jquery to give many pictures there must fully show.
So my question is, how I can make an if statement for when the browser width is for example 768px width, is must show two images...
$('.flexslider').flexslider({
animation: "slide",
animationLoop: true,
itemWidth: 320,
itemMargin: 0,
minItems: 2,
maxItems: 5,
start: function(slider){
$('body').removeClass('loading');
}
});
Check code on JSFiddle
You can use an if statement for widths like this:
if ($(window).width() < 960) {
alert('Less than 960');
}
else {
alert('More than 960');
}
... and to contain that, you might like to combine your document ready function with a window resize function.
$(document).ready(myfunction);
$(window).resize(myfunction);
function myfunction() {
// Pace the if/else here, do whatever
}
In terms of showing two images it think you should be able to be achieve that by setting slide widths and offsets in the flexslider function - or with css. here are the options i'm talking about:
itemWidth: 490, // or whatever is 1/2 of your width
itemMargin: 30, // experiment here!
minItems: 1, // or 2
Here's an edited version of your JS fiddle demo! http://jsfiddle.net/tM2a8/