Okay I'm not sure if I'm going about this in the right way or not, but here goes...
I'm writing a custom jQuery plugin to provide drop menu functionality with animation (and as a learning exercise so please no "Why not just use superduperwonderplugin-x").
I want to be able to animate the menu in different ways depending on user options (i.e fade, slide, drop etc.). At the moment each different animation is handled by a separate function within the plugin file but I'm not sure how to handle the callback functions (passing this back)!
-- i.e. The animation is only happening on the last element in the object's stack.
Here's my code:
/**
* Grizzly's Menuifier
*
* #author Chris.Leaper
* #version a1.0
*/
(function($){
$.fn.gmenu = function(options) {
/* Transitions:
- fade >> fadeIn / fadeOut
- slide >> slideDown / slideUp
- drop >> (different to above?)
- bounce >> (custom config transition=? and easing=bounce)
- stretch >> (custom config transition=? and easing=elastic)
- fold >> (custom) drop menu # half width then 'fold' out to full menu width
*/
// Set the plugin default options:
var defaults = {
levels: '1',
fit: 'auto',
easing: 'linear',
transition: 'slide',
speed: 500
};
options = $.extend(defaults, options); // Merge the user options with the plugin defaults
return this.each(function() {
var $this = $(this);
var opt = options;
var container;
var ul;
// Setup the container elements (parent DIV/NAV and UL)!
if( $this.is('ul') ) container = $(this).parent();
else container = $(this);
console.log('Container: ' + container.get(0).tagName + ' id=#' + container.attr('id') + ' class=' + container.attr('class'));
ul = container.children('ul:first-child');
console.log('UL: ' + ul);
// Set the UL's position to relative:
if($(ul).css('position') != 'relative') $(ul).css('position', 'relative');
var offset;
var menus = ul.children('li:has(ul)');
console.log('List Item: ' + menus);
menus.each(function(index, menu) {
$menu = $(menu);
console.log('Menu: ' + $menu);
// Set the menu LI's position to relative (contains the absolutely positioned child UL!)
if($menu.css('position') != 'relative') $menu.css('position', 'relative');
// Get the menu LI's position relative to the document (it's offset)
// -- This is only needed when positioning non-child elements
// (i.e. ID linked menu>submenu relationships as may be used for a separated DIV based menu!!)
// offset = menu.offest();
// Position the submenu according to it's parent
var submenu = $menu.children('ul');
console.log('Submenu: ' + submenu.get(0).tagName + ' id=#' + submenu.attr('id') + ' class=' + submenu.attr('class'));
setPosition(submenu, $menu.height());
switch(opt.transition) {
case 'bounce':
setSMBounce(menu, opt);
break;
case 'fade':
setSMFade(menu, opt);
break;
case 'fold':
setSMFold(menu, opt);
break;
case 'stretch':
setSMStretch(menu, opt);
break;
case 'slide':
default:
menu = setSMSlide(menu, opt);
}
});
debug(this);
});
};
})(jQuery);
function setPosition(submenu, height) {
$(submenu).css({
left: 0,
position: 'absolute',
top: height
}).hide();
}
function setSMSlide(menu, opt) {
$menu = $(menu);
console.log('SM Slide: ' + $menu.get(0));
$menu.first('a').mouseenter(function() {
console.log('Start SlideDown');
$menu.stop(true, true).slideDown(opt.speed, opt.easing);
console.log('Stop SlideDown');
});
$menu.first('a').mouseleave(function() {
console.log('Start SlideUp');
$menu.stop(true, true).slideUp(opt.speed, opt.easing);
console.log('Stop SlideUp');
});
}
I think that I should be using a (same) namespace based approach to defining my separate functions (object literal or something?) but I wasn't sure what this meant or how to do it.
Can anyone help me please?
To encapsulate your functions setPosition and setSMSlide (in your example) just define them inside your plugin function (the good place would be after definition of default variable. It would look something like that:
var defaults = {
levels: '1',
fit: 'auto',
easing: 'linear',
transition: 'slide',
speed: 500
},
setPosition = function(submenu, height) {...},
setSMSlide = function(menu, opt) {...};
Because of the way the scoping in Javascript works your setPosition and setSMSlide functions will be still accessible from inside of your gmenu declaration.
Related
I have the same problem as depicted here by mozman2:
"In my Django changelist there are lots of columns that means there is a scrollbar at the bottom of the list. Is it possible to get a scrollbar to appear at the top so I don't need to scroll down"
The solution from the given link seemed to help mozman2. However, I cannot reproduce it. Hence I tried copy-pasting the code from
https://github.com/avianey/jqDoubleScroll#readme
In particular, I copied this file from the repository to MyApp/static/admin/js/
jquery.doubleScroll.js
The file looks like this:
/*
* #name DoubleScroll
* #desc displays scroll bar on top and on the bottom of the div
* #requires jQuery
*
* #author Pawel Suwala - http://suwala.eu/
* #author Antoine Vianey - http://www.astek.fr/
* #version 0.5 (11-11-2015)
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Usage:
* https://github.com/avianey/jqDoubleScroll
*/
(function( $ ) {
jQuery.fn.doubleScroll = function(userOptions) {
// Default options
var options = {
contentElement: undefined, // Widest element, if not specified first child element will be used
scrollCss: {
'overflow-x': 'auto',
'overflow-y': 'hidden',
'height': '20px'
},
contentCss: {
'overflow-x': 'auto',
'overflow-y': 'hidden'
},
onlyIfScroll: true, // top scrollbar is not shown if the bottom one is not present
resetOnWindowResize: false, // recompute the top ScrollBar requirements when the window is resized
timeToWaitForResize: 30 // wait for the last update event (usefull when browser fire resize event constantly during ressing)
};
$.extend(true, options, userOptions);
// do not modify
// internal stuff
$.extend(options, {
topScrollBarMarkup: '<div class="doubleScroll-scroll-wrapper"><div class="doubleScroll-scroll"></div></div>',
topScrollBarWrapperSelector: '.doubleScroll-scroll-wrapper',
topScrollBarInnerSelector: '.doubleScroll-scroll'
});
var _showScrollBar = function($self, options) {
if (options.onlyIfScroll && $self.get(0).scrollWidth <= $self.width()) {
// content doesn't scroll
// remove any existing occurrence...
$self.prev(options.topScrollBarWrapperSelector).remove();
return;
}
// add div that will act as an upper scroll only if not already added to the DOM
var $topScrollBar = $self.prev(options.topScrollBarWrapperSelector);
if ($topScrollBar.length == 0) {
// creating the scrollbar
// added before in the DOM
$topScrollBar = $(options.topScrollBarMarkup);
$self.before($topScrollBar);
// apply the css
$topScrollBar.css(options.scrollCss);
$(options.topScrollBarInnerSelector).css("height", "20px");
$self.css(options.contentCss);
var scrolling = false;
// bind upper scroll to bottom scroll
$topScrollBar.bind('scroll.doubleScroll', function() {
if (scrolling) {
scrolling = false;
return;
}
scrolling = true;
$self.scrollLeft($topScrollBar.scrollLeft());
});
// bind bottom scroll to upper scroll
var selfScrollHandler = function() {
if (scrolling) {
scrolling = false;
return;
}
scrolling = true;
$topScrollBar.scrollLeft($self.scrollLeft());
};
$self.bind('scroll.doubleScroll', selfScrollHandler);
}
// find the content element (should be the widest one)
var $contentElement;
if (options.contentElement !== undefined && $self.find(options.contentElement).length !== 0) {
$contentElement = $self.find(options.contentElement);
} else {
$contentElement = $self.find('>:first-child');
}
// set the width of the wrappers
$(options.topScrollBarInnerSelector, $topScrollBar).width($contentElement.outerWidth());
$topScrollBar.width($self.width());
$topScrollBar.scrollLeft($self.scrollLeft());
}
return this.each(function() {
var $self = $(this);
_showScrollBar($self, options);
// bind the resize handler
// do it once
if (options.resetOnWindowResize) {
var id;
var handler = function(e) {
_showScrollBar($self, options);
};
$(window).bind('resize.doubleScroll', function() {
// adding/removing/replacing the scrollbar might resize the window
// so the resizing flag will avoid the infinite loop here...
clearTimeout(id);
id = setTimeout(handler, options.timeToWaitForResize);
});
}
});
}
}( jQuery ));
I then told django about the file using
class Media:
js = (
'//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js', # jquery
'js/jquery.doubleScroll.js', # project static folder
)
Afterwards I followed with a collectstatic-command:
...
Copying '/MyApp/static/admin/js/jquery.doubleScroll.js'
...
1 static file copied to '/MyApp/static', 123 unmodified.
However, the horizontal scroll-bar on top doesn't show.
In the github repository it is suggested to use the double-scrollbar by
$(document).ready(function() {
$('.double-scroll').doubleScroll();
});
Where do I put this? I tried using it on the same .js-File instead of the starting
(function( $ ) {
...
};
This didn't help neither.
I guess I am missing out on something?
I solved my problem by knowing the syntax for django - jquery.
Here's how:
I got 2 new .js - Files, one which just calls the function of the double-scroll provided (calling.js) and the js-Files of the authors (doubleScroll.js) itself.
In your adminModel in admin.py you put in:
class Media:
js = ('//ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js',
'admin/js/doubleScroll.js',
'admin/js/calling.js',)
The '//ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js' - link is necessary to make native jquery possible to run, if I understood correctly.
calling.js:
django.jQuery(document).ready(function() {
setTimeout(() => $('.results').doubleScroll({resetOnWindowResize: true}), 245);
});
doubleScroll.js:
/*
* #name DoubleScroll
* #desc displays scroll bar on top and on the bottom of the div
* #requires jQuery
*
* #author Pawel Suwala - http://suwala.eu/
* #author Antoine Vianey - http://www.astek.fr/
* #version 0.5 (11-11-2015)
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Usage:
* https://github.com/avianey/jqDoubleScroll
*/
(function( $ ) {
jQuery.fn.doubleScroll = function(userOptions) {
// Default options
var options = {
contentElement: undefined, // Widest element, if not specified first child element will be used
scrollCss: {
'overflow-x': 'auto',
'overflow-y': 'hidden',
'height': '20px'
},
contentCss: {
'overflow-x': 'auto',
'overflow-y': 'hidden'
},
onlyIfScroll: true, // top scrollbar is not shown if the bottom one is not present
resetOnWindowResize: false, // recompute the top ScrollBar requirements when the window is resized
timeToWaitForResize: 30 // wait for the last update event (usefull when browser fire resize event constantly during ressing)
};
$.extend(true, options, userOptions);
// do not modify
// internal stuff
$.extend(options, {
topScrollBarMarkup: '<div class="doubleScroll-scroll-wrapper"><div class="doubleScroll-scroll"></div></div>',
topScrollBarWrapperSelector: '.doubleScroll-scroll-wrapper',
topScrollBarInnerSelector: '.doubleScroll-scroll'
});
var _showScrollBar = function($self, options) {
if (options.onlyIfScroll && $self.get(0).scrollWidth <= $self.width()) {
// content doesn't scroll
// remove any existing occurrence...
$self.prev(options.topScrollBarWrapperSelector).remove();
return;
}
// add div that will act as an upper scroll only if not already added to the DOM
var $topScrollBar = $self.prev(options.topScrollBarWrapperSelector);
if ($topScrollBar.length == 0) {
// creating the scrollbar
// added before in the DOM
$topScrollBar = $(options.topScrollBarMarkup);
$self.before($topScrollBar);
// apply the css
$topScrollBar.css(options.scrollCss);
$(options.topScrollBarInnerSelector).css("height", "20px");
$self.css(options.contentCss);
var scrolling = false;
// bind upper scroll to bottom scroll
$topScrollBar.bind('scroll.doubleScroll', function() {
if (scrolling) {
scrolling = false;
return;
}
scrolling = true;
$self.scrollLeft($topScrollBar.scrollLeft());
});
// bind bottom scroll to upper scroll
var selfScrollHandler = function() {
if (scrolling) {
scrolling = false;
return;
}
scrolling = true;
$topScrollBar.scrollLeft($self.scrollLeft());
};
$self.bind('scroll.doubleScroll', selfScrollHandler);
}
// find the content element (should be the widest one)
var $contentElement;
if (options.contentElement !== undefined && $self.find(options.contentElement).length !== 0) {
$contentElement = $self.find(options.contentElement);
} else {
$contentElement = $self.find('>:first-child');
}
// set the width of the wrappers
$(options.topScrollBarInnerSelector, $topScrollBar).width($contentElement.outerWidth());
$topScrollBar.width($self.width());
$topScrollBar.scrollLeft($self.scrollLeft());
}
return this.each(function() {
var $self = $(this);
_showScrollBar($self, options);
// bind the resize handler
// do it once
if (options.resetOnWindowResize) {
var id;
var handler = function(e) {
_showScrollBar($self, options);
};
$(window).bind('resize.doubleScroll', function() {
// adding/removing/replacing the scrollbar might resize the window
// so the resizing flag will avoid the infinite loop here...
clearTimeout(id);
id = setTimeout(handler, options.timeToWaitForResize);
});
}
});
}
}( jQuery ));
Dont forget to run
collectstatic
jQuery is included in Django, so only one .js file is required.
1. admin.py
# Created by BaiJiFeiLong#gmail.com at 2022/5/5
from django.contrib import admin
from django.contrib.auth.models import User
class UserAdmin(admin.ModelAdmin):
model = User
class Media(object):
js = (
"js/doubleScroll.js",
)
2. js/doubleScroll.js
/*
* #name DoubleScroll
* #desc displays scroll bar on top and on the bottom of the div
* #requires jQuery
*
* #author Pawel Suwala - http://suwala.eu/
* #author Antoine Vianey - http://www.astek.fr/
* #version 0.5 (11-11-2015)
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Usage:
* https://github.com/avianey/jqDoubleScroll
*/
(function( $ ) {
jQuery.fn.doubleScroll = function(userOptions) {
// Default options
var options = {
contentElement: undefined, // Widest element, if not specified first child element will be used
scrollCss: {
'overflow-x': 'auto',
'overflow-y': 'hidden',
'height': '20px'
},
contentCss: {
'overflow-x': 'auto',
'overflow-y': 'hidden'
},
onlyIfScroll: true, // top scrollbar is not shown if the bottom one is not present
resetOnWindowResize: false, // recompute the top ScrollBar requirements when the window is resized
timeToWaitForResize: 30 // wait for the last update event (usefull when browser fire resize event constantly during ressing)
};
$.extend(true, options, userOptions);
// do not modify
// internal stuff
$.extend(options, {
topScrollBarMarkup: '<div class="doubleScroll-scroll-wrapper"><div class="doubleScroll-scroll"></div></div>',
topScrollBarWrapperSelector: '.doubleScroll-scroll-wrapper',
topScrollBarInnerSelector: '.doubleScroll-scroll'
});
var _showScrollBar = function($self, options) {
if (options.onlyIfScroll && $self.get(0).scrollWidth <= Math.round($self.width())) {
// content doesn't scroll
// remove any existing occurrence...
$self.prev(options.topScrollBarWrapperSelector).remove();
return;
}
// add div that will act as an upper scroll only if not already added to the DOM
var $topScrollBar = $self.prev(options.topScrollBarWrapperSelector);
if ($topScrollBar.length == 0) {
// creating the scrollbar
// added before in the DOM
$topScrollBar = $(options.topScrollBarMarkup);
$self.before($topScrollBar);
// apply the css
$topScrollBar.css(options.scrollCss);
$(options.topScrollBarInnerSelector).css("height", "20px");
$self.css(options.contentCss);
var scrolling = false;
// bind upper scroll to bottom scroll
$topScrollBar.bind('scroll.doubleScroll', function() {
if (scrolling) {
scrolling = false;
return;
}
scrolling = true;
$self.scrollLeft($topScrollBar.scrollLeft());
});
// bind bottom scroll to upper scroll
var selfScrollHandler = function() {
if (scrolling) {
scrolling = false;
return;
}
scrolling = true;
$topScrollBar.scrollLeft($self.scrollLeft());
};
$self.bind('scroll.doubleScroll', selfScrollHandler);
}
// find the content element (should be the widest one)
var $contentElement;
if (options.contentElement !== undefined && $self.find(options.contentElement).length !== 0) {
$contentElement = $self.find(options.contentElement);
} else {
$contentElement = $self.find('>:first-child');
}
// set the width of the wrappers
$(options.topScrollBarInnerSelector, $topScrollBar).width($contentElement.outerWidth());
$topScrollBar.width($self.width());
$topScrollBar.scrollLeft($self.scrollLeft());
}
return this.each(function() {
var $self = $(this);
_showScrollBar($self, options);
// bind the resize handler
// do it once
if (options.resetOnWindowResize) {
var id;
var handler = function(e) {
_showScrollBar($self, options);
};
$(window).bind('resize.doubleScroll', function() {
// adding/removing/replacing the scrollbar might resize the window
// so the resizing flag will avoid the infinite loop here...
clearTimeout(id);
id = setTimeout(handler, options.timeToWaitForResize);
});
}
});
}
}( jQuery ));
document.addEventListener("DOMContentLoaded", () => {
django.jQuery('.results').doubleScroll({resetOnWindowResize: true});
})
3. Restart Django server
Maybe python manage.py collectstatic is required.
Press F12 in your browser, make sure the .js file is loaded correctly.
I have used jQuery 1.12.2 with animate.css which populates a progress bar successfully. Now I.m trying to only make the progress bar load after I scroll down to it as is currently loads straight away. What's the point in having this awesome feature when it has already been loaded when it is somewhere down the bottom of the page?
I have created a JSFiddle here. I know the JavaScript is a little messy and can be written in a more cleaner way but please excuse me as I am new to JS and trying to make this work first. Can anyone help?
$('#myid').goalProgress({
goalAmount: 100,
currentAmount: 75,
textBefore: 'myid ',
textAfter: ''
});
});
goalProgress is a whole different class:
!function($){
$.fn.extend({
goalProgress: function(options) {
var defaults = {
goalAmount: 100,
currentAmount: 50,
speed: 1000,
textBefore: '',
textAfter: '',
milestoneNumber: 70,
milestoneClass: 'almost-full',
callback: function() {}
}
var options = $.extend(defaults, options);
return this.each(function(){
var obj = $(this);
// Collect and sanitize user input
var goalAmountParsed = parseInt(defaults.goalAmount);
var currentAmountParsed = parseInt(defaults.currentAmount);
// Calculate size of the progress bar
var percentage = (currentAmountParsed / goalAmountParsed) * 100;
var milestoneNumberClass = (percentage > defaults.milestoneNumber) ? ' ' + defaults.milestoneClass : ''
// Generate the HTML
var progressBar = '<div class="progressBar">' + defaults.textBefore + defaults.textAfter + '</div>';
var progressBarWrapped = '<div class="goalProgress' + milestoneNumberClass + '">' + progressBar + '</div>';
// Append to the target
obj.append(progressBarWrapped);
// Ready
var rendered = obj.find('div.progressBar');
// Remove Spaces
rendered.each(function() {
$(this).html($(this).text().replace(/\s/g, ' '));
});
// Animate!
rendered.animate({width: percentage +'%'}, defaults.speed, defaults.callback);
if(typeof callback == 'function') {
callback.call(this)
}
});
}
});
}(window.jQuery);
Instead of running this
$('#myid').goalProgress({
goalAmount: 100,
currentAmount: 75,
textBefore: 'myid ',
textAfter: ''
});
});
on .ready event
Try to run it on scroll event.
For example make an algorithm to check if this #mydiv is in your viewport and then trigger this function.
Or use some ready plugin. For example : http://scrollmagic.io/
I have a premium wordpress theme which came with a built in full page slider. It integrates nicely into my website but it displays full page and the information underneath is being lost. The slider is responsive to the window size, I'd like it to be only 60%. Please can someone help:
(function ($) {
"use strict";
$.fn.maximage = function (settings, helperSettings) {
var config;
if (typeof settings == 'object' || settings === undefined) config = $.extend( $.fn.maximage.defaults, settings || {} );
if (typeof settings == 'string') config = $.fn.maximage.defaults;
/*jslint browser: true*/
$.Body = $('body');
$.Window = $(window);
$.Scroll = $('html, body');
$.Events = {
RESIZE: 'resize'
};
this.each(function() {
var $self = $(this),
preload_count = 0,
imageCache = [];
/* --------------------- */
// #Modern
/*
MODERN BROWSER NOTES:
Modern browsers have CSS3 background-size option so we setup the DOM to be the following structure for cycle plugin:
div = cycle
div = slide with background-size:cover
div = slide with background-size:cover
etc.
*/
var Modern = {
setup: function(){
if($.Slides.length > 0){
// Setup images
for(var i in $.Slides) {
// Set our image
var $img = $.Slides[i];
// Create a div with a background image so we can use CSS3's position cover (for modern browsers)
$self.append('<div class="mc-image ' + $img.theclass + '" title="' + $img.alt + '" style="background-image:url(\'' + $img.url + '\');' + $img.style + '" data-href="'+ $img.datahref +'">'+ $img.content +'</div>');
}
// Begin our preload process (increments itself after load)
Modern.preload(0);
// If using Cycle, this resets the height and width of each div to always fill the window; otherwise can be done with CSS
Modern.resize();
}
},
preload: function(n){
// Preload all of the images but never show them, just use their completion so we know that they are done
// and so that the browser can cache them / fade them in smoothly
// Create new image object
var $img = $('<img/>');
$img.load(function() {
// Once the first image has completed loading, start the slideshow, etc.
if(preload_count==0) {
// Only start cycle after first image has loaded
Cycle.setup();
// Run user defined onFirstImageLoaded() function
config.onFirstImageLoaded();
}
// preload_count starts with 0, $.Slides.length starts with 1
if(preload_count==($.Slides.length-1)) {
// If we have just loaded the final image, run the user defined function onImagesLoaded()
config.onImagesLoaded( $self );
}else{
// Increment the counter
preload_count++;
// Load the next image
Modern.preload(preload_count);
}
});
// Set the src... this triggers begin of load
$img[0].src = $.Slides[n].url;
// Push to external array to avoid cleanup by aggressive garbage collectors
imageCache.push($img[0]);
},
resize: function(){
// Cycle sets the height of each slide so when we resize our browser window this becomes a problem.
// - the cycle option 'slideResize' has to be set to false otherwise it will trump our resize
$.Window
.bind($.Events.RESIZE,
function(){
// Remove scrollbars so we can take propper measurements
$.Scroll.addClass('mc-hide-scrolls');
// Set vars so we don't have to constantly check it
$.Window
.data('h', Utils.sizes().h)
.data('w', Utils.sizes().w);
// Set container and slides height and width to match the window size
$self
.height($.Window.data('h')).width($.Window.data('w'))
.children()
.height($.Window.data('h')).width($.Window.data('w'));
// This is special noise for cycle (cycle has separate height and width for each slide)
$self.children().each(function(){
this.cycleH = $.Window.data('h');
this.cycleW = $.Window.data('w');
});
// Put the scrollbars back to how they were
$($.Scroll).removeClass('mc-hide-scrolls');
});
}
}
Thanks in advance. James
Generally, the themes are very customizable on the admin panel. So, you should check it out before you changing it by hand.
If you dont find for customization on the admin panel (and on the theme developer page), as you may be know, when the themes are responsive they are using some framework like bootstrap, foundation, whatever. And then, the slider have to have a css class like "large-12", it should be modified to change its size, for example "large-8", then the slider size will be 8/12.
I hope it help you!
I'm making a vertical parallax scrolling site with ScrollMagic which includes a navigation menu at the top to link within the site.
The menu itself works correctly when no parallax animation is applied to the scroll but when the parallax is added (ie the 2nd section moves up over the intro section), it seems unable to take the reduction in overall height into account when moving to the section, so it overshoots.
Here is some code:
var site = {
smController : {},
init : function () {
site.setupScroll();
site.setupMainNavigation();
site.setupAnimation();
},
setupScroll : function () {
// init the smController
var controller = new ScrollMagic({
globalSceneOptions: {
triggerHook: "onLeave"
}
});
site.smController = controller;
},
setupMainNavigation : function () {
$('.menuclick').on('click', function (event) {
event.preventDefault();
var anchor = $(this),
sectionId = $(anchor.attr('href'));
site.scrollToSection(sectionId);
});
},
/**
* uses tweenlite and scrolltoplugin from greensock
* #param {string} sectionId id of section to scroll to
* #return {void}
*/
scrollToSection : function (sectionId) {
var scrollYPos = $(sectionId).offset().top;
TweenLite.to(window, 0.5, { scrollTo:{ y: scrollYPos } });
},
setupAnimation : function () {
// parallax animation - move marginTop back by 100%
var tween = new TimelineMax()
.to('#section1', 2, { marginTop: '-100%', ease:Linear.easeNone });
var controller = site.smController,
scene = new ScrollScene({ duration: 500 })
.setTween(tween)
.addTo(controller);
// show indicators (requires debug extension)
scene.addIndicators();
}
};
$(document).ready(function () {
site.init();
});
Does anyone have a strategy to deal with moving (parallax) sections like this please?
Thanks
In ScrollMagic 1.1 you can now provide custom scroll functions AND scroll to the beginning of a specific scene.
Read more here:
http://janpaepke.github.io/ScrollMagic/docs/ScrollMagic.html#scrollTo
I would also strongly suggest not to use animated elements as scroll targets, because their position might be different before and after initiating scroll.
If you have elements that influence the DOM height, try to take them out of the DOM flow.
You can do this for example by adding an element as a placeholder and setting your element as positioned absolutely.
hope this helps.
J
I did something like this, using a similar setup to the demo page
new ScrollMagic.Scene(settings)
.setPin(slides[i])
.on('enter', function () {
var $trigger = $(this.triggerElement()),
$nextSlide = $trigger.parent().next().find('.slide');
/*
* If there's a next slide,
* update the href of the button
* to target the next slide
* otherwise, we're at the end;
* toggle the button state so it targets
* the top of the page
*/
if ($nextSlide.length) {
$('.btn-scroll').attr('href', '#' + $nextSlide.attr('id'));
} else {
$('.btn-scroll').attr('href', '#').addClass('up');
}
})
.on('leave', function (event) {
var $trigger = $(this.triggerElement()),
$firstSlide = $('.slide:first');
/*
* If we're going back up and we pass
* the first slide, update the button
* so it targets the first slide
*/
if (event.scrollDirection === 'REVERSE' && ($trigger.offset().top === $firstSlide.offset().top)) {
$('.btn-scroll').attr('href', originalTarget).removeClass('up');
}
})
.addTo(controller);
It just needs an anchor link with the href set to the first slide.
and something like this to handle the scroll:
var scrollToContent = function (target, speed) {
if (target === '#') {
target = $('body');
} else {
target = $(target);
}
speed = typeof speed !== 'undefined' ? speed : 'slow';
$('html, body').animate({
scrollTop: target.offset().top
}, speed);
}
<script language="javascript">
$(document).ready(function($) {
var methods = {
init: function(options) {
this.children(':first').stop();
this.marquee('play');
},
play: function() {
var marquee = this,
pixelsPerSecond = 100,
firstChild = this.children(':first'),
totalHeight = 0,
difference,
duration;
// Find the total height of the children by adding each child's height:
this.children().each(function(index, element) {
totalHeight += $(element).innerHeight();
});
// The distance the divs have to travel to reach -1 * totalHeight:
difference = totalHeight + parseInt(firstChild.css('margin-top'), 10);
// The duration of the animation needed to get the correct speed:
duration = (difference/pixelsPerSecond) * 1000;
// Animate the first child's margin-top to -1 * totalHeight:
firstChild.animate(
{ 'margin-top': -1 * totalHeight },
duration,
'linear',
function() {
// Move the first child back down (below the container):
firstChild.css('margin-top', marquee.innerHeight());
// Restart whole process... :)
marquee.marquee('play');
}
);
},
pause: function() {
this.children(':first').stop();
}
};
$.fn.marquee = function(method) {
// Method calling logic
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.marquee');
}
};
})(jQuery);
var marquee = $('#marquee');
marquee.marquee();
marquee.hover(function() {
marquee.marquee('pause');
}, function() {
marquee.marquee('play');
});
</script>
<style type="text/css">
#marquee {
margin:inherit;
width:auto;
height:inherit
}
</style>
I would like to create a scroller using jquery but I fail. The above code is the marquee I use to scroll up my items. And I am using it as below,
<html>
<body>
<div class="content">
<div id="marquee">
<ul>
<li>...</li>
....
</ul>
</div>
</div></body>
</html>
But it doesn't scroll at all, is there something incorrect in the code I am using you can find for me ?
Not sure if margin-top should work for this at all.
Try using position:relative for holder block(marquee) and position:absolute for content (ul). And update top instead of margin top. But in this case you may need to specify height and overflow:hidden for marquee div. Another options is to set height and oveflow:hidden for marquee, but leave position default. And scroll content using scrollTop or with some similar jquery functions.