I have this javascript code that scrolls a div depending on the mouse position.
Ive got the code working, the problem is its a bit jittery. I was wondering if anybody could give me advice on how to optimise it so it runs smoothly!
To view the code please visit my jsfiddle:
http://jsfiddle.net/ENhwT/3/
I realised i was going WELL too far with this, and the solution was easy.
You calculate the new scroll position based on the EXACT mouse Position... Code Follows:
$(window).load(function(){
var container = $("#PortfolioReel");
var elem = $("#PortfolioReel div");
var max_pos = container.width();
var max_scroll = elem.width() - max_pos;
var differential = max_scroll / max_pos;
$("#PortfolioReel").mousemove(function(e){
var pos = (e.pageX - this.offsetLeft) + 1;
var scr = Math.round(pos * differential);
container.scrollLeft(scr);
});
});
You set the position in fixed large steps, so it's 'jumping'. You have to iterate in smaller steps until you reach the target position.
You shouldn't use six fixed position values, but calculate new values in timesteps.
You could use something like this to make a smoother transition:
http://api.jquery.com/animate/
Sample
Something like this should be working:
elem.animate({
scrollLeft: current + 25
}, 500, function() {
// Animation complete.
});
Related
I'd like to know if there's a way of scrolling content according to the position of the cursor ? After hours of research found this carousel plugin http://www.convergent-evolution.co.uk/resources/jquery-plugins/scrolling-carousel/ however it doesn't seem like I can do free (diagonal) scrolling.
You will need to use jquery or javascript to get the mouse position of the client X and Y to pinpoint their position.
var x=event.clientX;
var y=event.clientY;
var windowHeight = window.innerHeight //and
var windowWidth = window.innerWidth
will also help.
if(x > windowWidth-400) {
$('html, body')
.animate({ scrollRight: 400 });
});
}
I am pretty sire that will do the trick just do the same for y cords of your mouse and you should be good to go. :)
Simple, I just would like to have it so when a user is dragging an item and they reach the very bottom or top of the viewport (10px or so), the page (about 3000px long) gently scrolls down or up, until they move their cursor (and thus the item being dragged) out of the region.
An item is an li tag which uses jquery to make the list items draggable. To be specific:
../jquery-ui-1.8.14.custom.min.js
http://code.jquery.com/jquery-1.6.2.min.js
I currently use window.scrollBy(x=0,y=3) to scroll the page and have the variables of:
e.pageY ... provides absolute Y-coordinates of cursor on page (not relative to screen)
$.scrollTop() ... provides offset from top of page (when scroll bar is all the way up, it is 0)
$.height()... provides the height of viewable area in the user's browser/viewport
body.offsetHeight ... height of the entire page
How can I achieve this and which event best accommodates this (currently its in mouseover)?
My ideas:
use a an if/else to check if it is in top region or bottom, scroll up if e.pageY is showing it is in the top, down if e.page& is in bottom, and then calling the $('li').mouseover() event to iterate through...
Use a do while loop... this has worked moderately well actually, but is hard to stop from scrolling to far. But I am not sure how to control the iterations....
My latest attempt:
('li').mouseover(function(e) {
totalHeight = document.body.offsetHeight;
cursor.y = e.pageY;
var papaWindow = window;
var $pxFromTop = $(papaWindow).scrollTop();
var $userScreenHeight = $(papaWindow).height();
var iterate = 0;
do {
papaWindow.scrollBy(0, 2);
iterate++;
console.log(cursor.y, $pxFromTop, $userScreenHeight);
}
while (iterate < 20);
});
Works pretty well now, user just needs to "jiggle" the mouse when dragging items sometimes to keep scrolling, but for scrolling just with mouse position its pretty solid. Here is what I finally ended up using:
$("li").mouseover(function(e) {
e = e || window.event; var cursor = { y: 0 }; cursor.y = e.pageY; //Cursor YPos
var papaWindow = parent.window;
var $pxFromTop = $(papaWindow).scrollTop();
var $userScreenHeight = $(papaWindow).height();
if (cursor.y > (($userScreenHeight + $pxFromTop) / 1.25)) {
if ($pxFromTop < ($userScreenHeight * 3.2)) {
papaWindow.scrollBy(0, ($userScreenHeight / 30));
}
}
else if (cursor.y < (($userScreenHeight + $pxFromTop) * .75)) {
papaWindow.scrollBy(0, -($userScreenHeight / 30));
}
}); //End mouseover()
This won't work as the event only fires while you're mouse is over the li.
('li').mouseover(function(e) { });
You need to be able to tell the position of the mouse relative to the viewport when an item is being dragged. When the users starts to drag an item attach an 'mousemove' event to the body and then in that check the mouse position and scroll when necessary.
$("body").on("mousemove", function(event) {
// Check mouse position - scroll if near bottom or top
});
Dont forget to remove your event when the user stops dragging.
$("body").off("mousemove", function(event) {
// Check mouse position - scroll if near bottom or top
});
This may not be exactly what you want, but it might help. It will auto-scroll when the mouse is over the 'border of the screen' (a user defined region). Say you have a 40px wide bar on the right of the screen, if the mouse reaches the first 1px, it will start scrolling. Each px you move into it, the speed will increase. It even has a nice easing animation.
http://www.smoothdivscroll.com/v1-2.htm
I get a weekly newsletter (email) from CodeProject, and it had some stuff that certainly looks like it will solve my problem... hopefully this can help others:
http://johnpolacek.github.com/scrollorama/ -- JQuery based and animates the scroll
https://github.com/IanLunn/jQuery-Parallax -- JQuery based, similar to above
http:// remysharp. com/2009/01/26/element-in-view-event-plugin/ -- JQuery, detects whether an element is currently in view of the user (super helpful for this issue!)
Also the site in #2 had some interesting code:
var windowHeight = $window.height();
var navHeight = $('#nav').height() / 2;
var windowCenter = (windowHeight / 2);
var newtop = windowCenter - navHeight;
//ToDo: Find a way to use these vars and my original ones to determine scroll regions
I'm trying to counteract an adjustment to the height of an element which is above the scroll offset by calculating the difference in height and then updating the current scroll position to account for it.
The problem is that there's no way that I can prevent a very quick flickering artefact. Whether I adjust the element's height and then the scroll position, or vice versa, I can't seem to prevent a quick visual jump.
Does anyone know how this could be overcome? I want these to operations to happen at the same time with no rendering in-between but I'm not sure if it's possible.
// Setup
...
var myElement = ...
var oldHeight = ...
var scrollOffset = window.scrollY;
var newHeight = 100;
var diff = newHeight - oldHeight;
// Determine if we need to counteract new size
var adjustScroll = (absoluteOffset(myElement) < scrollOffset);
// Adjust size
myElement.style.height = newHeight+'px';
// Adjust scroll to counteract the new height
if (adjustScroll) window.scrollTo(0, scrollOffset+diff);
I'm working with WebKit, specifically on iOS.
for webkit you can use CSS transitions/animations to smooth this but it's still sound like you are going the wrong way to begin with. I am sure that whatever is it you are trying to do can be solved purely with CSS (maybe with some very minimal Javaqscript). Post an example of you HTML + CSS + JS.
You could use scrollIntoView with timers to simulate multiple threads.
Or you could do it inside a document fragment beforehand.
Sorry to be reviving an old post here, but i came across this looking for a solution to a similar problem to do with browser resizing.
Stackoverflow user James Kyle created this little jsfiddle using jQuery that attempts to maintain scroll position as best as possible when a page is resized
var html = $('html'),
H = html.outerHeight(true),
S = $(window).scrollTop(),
P = S/H;
$(window).scroll(function() {
S = $(window).scrollTop();
P = S/H;
});
$(window).resize(function() {
H = html.outerHeight(true);
$(window).scrollTop(P*H);
});
http://jsfiddle.net/JamesKyle/RmNap/
you could try using this same code and trigger a 'resize' event on the html when the image has loaded by using a jQuery library like imagesLoaded
So I've been trying to figure this out for awhile and can't seem to get it.
I use a navigation consisting of circles (see website below) and when the user clicks on one, it forwards him/her to the corresponding slide.
When you click around, it will sometimes slide all the way back to the beginning of the window (margin-left = 0). If it doesn't do it at first, just click around for a second or two and you'll eventually see it.
http://dan.stargroupdev.com/
Here's the code that's buggy:
$("#footer-slidenav .links a").click(function () {
// Get nav index
var slidenum = $(this).attr("id").slice(3);
// Setup slide selector with string to avoid issues
var slidetext = ".slide:eq(" + slidenum + ")";
slidenum = $(slidetext).offset().left;
console.log("Top: " + slidenum);
var offset2 = 0;
// Find window offset to center slide if screen is bigger than 1000px (size of one slide)
if (($(window).width() - 1000) / 2 > 0) {
offset2 = ($(window).width() - 1000) / 2;
}
// Slide window to slide # that was clicked
$("html:not(:animated), body:not(:animated)").animate({
scrollLeft: slidenum
}, 1000, function () {
console.log("Middle: " + slidenum);
// Callback to center slide and give a nice little animated touch
slidenum = $(slidetext).offset().left;
console.log("Bottom: " + slidenum);
$("html:not(:animated), body:not(:animated)").animate({
scrollLeft: (slidenum - offset2)
}, "fast");
});
return false;
});
I tried things like $("html:not(:animated), body:not(:animated)") along with a few other similar possible solutions, but the bug is still there.
Any advice would be great and I'm more than happy to entertain any ideas you guys might have.
Thanks.
Turns out I had a leftover piece of code in another JS file. Sorry for wasting your time guys, that's why it was getting messed up.
I appreciate your answers though.
Ill propose an entirely new solution(mostly new)
$("#footer-slidenav .links a").click(function () {
var slidenum = $(this).attr("id").slice(3);
var slidetext = ".slide:eq(" + slidenum + ")";
offset = $(slidetext).position().left;
console.log(offset );
$("body").animate({
scrollLeft: offset
});
});
Could you give it a try?
my suggestion is to test the site without the class front on body. The script http://dan.stargroupdev.com/sites/all/themes/starsite/js/starsite.js use this class with result to create the unwanted behavior I think. If I remove it with firebug it works ok for me. Check it and give feedback to see if this is true.
First of all can I suggest Arial Flesler's scrollTo plugin? It's awesome and works like a charm.
You can use offsets to center the final position.
If you want some kind of easing then you can use them to make the animation look more natural. What about an elastic animation?
I've been using this plugin for over one year, without finding any problem.
Also, remember to .stop() the scrolled/animated element.
I'm trying to use the left variable to replace '1493' in this code. It works fine when it's a number but when I changed it over to use 'left' the if statement stops working.
$(document).scroll(function () {
var width = $(document).width();
var left = $(document).scrollLeft();
var postCount = $(".post").length;
var columnLength = ( width - ((postCount*743) - 1493)) - (width-(postCount*743));
if(left >= columnLength) {
$(".num").text(left);
}
});
Does anyone have any ideas where I'm going wrong with this? Any pointers would be great.
You may need to force it to be an integer:
var left = parseInt($(document).scrollLeft());
Lets take a look at the math you have really quick.
var columnLength = ( width - ((postCount*743) - 1493)) - (width-(postCount*743));
You are basically cancelling out width, and (postCount*743). It leaves you with --1493 which is positive 1493. The following would have the same effect:
var columnLength = 1493;
So, the reason the if statement fires when you put in the static value 1493, is because columnLength ALWAYS equals 1493 which, of course satisfies this condition:
if (1493 >= columnLength)
You could as easily write:
if (1493 >= 1493)
That said, it should still, theoretically fire when left becomes greater than or equal to 1493. But left is the current horizontal scroll position in pixels. It would be a HUGELY wide page to hit a scroll position of 1493.
Edit: Here's a fiddle to give an idea of how fast the scroll position increases: http://jsfiddle.net/vdQ7B/16/
EDIT 2:
Here is an update in response to your comment.
As I understand it, you were trying to get a horizontal scrollbar that would, essentially, scroll forever.
Please see the following fiddle for a demo: http://jsfiddle.net/vdQ7B/40/
The code is below:
$(document).scroll(function () {
var width = $(document).width();
var left = $(document).scrollLeft();
var viewportwidth = window.innerWidth;
// If our scrollbar gets to the end,
// add 50 more pixels. This could be set
// to anything.
if((left + viewportwidth) === width) {
$("body").css("width", width + 50);
}
});
Per the comments in the code, we simply increase the width of the body if we determine we've reached the end. scrollLeft() will only tell us the number of pixels that are currently not visible to the left of the viewable area. So, we need to know how much viewable area we have, and how much is hidden to the left to know if we've scrolled all the way to the end.
If you have a scroll bar on an inner element, like a div, you'd need to update with width of the div, not the body.
Note: You may also need to use $(window) instead of $(document) to get scrollLeft() to work across all browsers.
Note: See here about using "innerWidth". There are some compatibility issues, and you may need to expand it a bit to handle other cases (IE6).