How to implement autoscroll to follow my div - javascript

I've looked at several tutorials online and a few similar questions on SO but not been able to work out how to make the screen autoscroll left and right so that my #sheep stays in the centre of the screen.
I'm using javascript and jquery to move a simple div across the screen.
Here's my jsfiddle
http://jsfiddle.net/JosephByrne/CkkVr/
What's the best method of making the screen follow my div?

I think you're trying to move the wrong element left/right. I think you need to leave your sheep in the middle of the screen then move the background.
Something like:
var walkLeft = function() {
$('#background').animate({left:"-=10px",top:"-=2px"}, 100);
$('#background').animate({left:"-=10px",top:"+=2px"}, 100);
};
var walkRight = function() {
$('#background').animate({left:"+=10px",top:"-=2px"}, 100);
$('#background').animate({left:"+=10px",top:"+=2px"}, 100);
};
http://jsfiddle.net/CkkVr/22/ (you'll need to "jump right" to see the sheep), but you get the general idea!

You need something similar to this:
function scrollContainer() {
var $sheep = $("#sheep");
$("body").scrollLeft($sheep.position().left + $sheep.width());
}
That utilizes jQuery's scrollLeft() function as well as the position() function (on the sheep).
You just need to keep messing with the math until it works out properly...
I've implemented it on the "jump" functions here:
http://jsfiddle.net/Dxe8a/11/
function scrollContainer() {
var $sheep = $("#sheep");
var $body = $("body");
var windowWidthOver2 = ($(window).width()/2);
var pos = $sheep.position().left + windowWidthOver2 - $sheep.width() - 80;
if($body.width() <= (pos + windowWidthOver2 - $sheep.width() - 80)) {
$body.width($body.width() + windowWidthOver2);
}
$body.scrollLeft(pos);
}
You should alter it so that it looks a bit better, but at least it follows your sheep somewhat.
P.S. it works better in fiddle if you view it in "/show": http://jsfiddle.net/Dxe8a/11/show

Related

Detecting whether a click has been made to the left side or on the right side of div in react

Hey guys i have a div in react where i need to find out whether the click has been made to the left side or the right side of the div. Until now i was using jquery but i came to know its better to avoid jquery with react . So any solution to this without using jquery as i am pretty new to the react side?
This was what i was doing with the help of jquery
HTML
<div onClick={()=>this.calcClick()}>....</div>
JS
calcCLick = () => {
var position = ""
$("div").click(function (e) {
var pWidth = $(this).innerWidth(); //use .outerWidth() if you want borders
var pOffset = $(this).offset();
var x = e.pageX - pOffset.left;
// console.log(pWidth, pOffset, x);
if (pWidth / 2 > x) {
console.log("left");
position = "left"
}
// $(this).text('left');
else {
console.log("right");
position = "right"
}
})
To achieve this, you can use the useRef hook of React itself and the getBoundClientRect().width to get the width of the div like said Chris in the comment above.
After this, you can get the mouse position in the div with the nativeEvent of the event.
Check this sandbox if you want an example

jQuery move background to follow element positioned using CSS Animations

I got an application where I'm moving an image around the page using CSS3 Animations the idea is you click a button and the next animation runs and this way the "sprite" moves around a map.
However on mobile I was asked to keep the size of the map the same as desktop but instead move the map instead of the sprite, my question is how can I make that work?
My current (really early) code looks like this:
$(document).on("boatAnimationStarted", function(event) {
window.isAnimating = true;
var boatElement = $("#boat-sprite");
var backgroundElement = $("#background");
var backgroundWidth = backgroundElement.width();
var backgroundHeight = backgroundElement.height();
var windowSize = { width: $(window).width(), height: $(window).height() };
var originalOffset = boatElement.offset();
window.animationInterval = setInterval(function() {
var boatOffset = boatElement.offset();
var working = {
top: originalOffset.top - (boatOffset.top / 2),
left: originalOffset.left - (boatOffset.left / 2),
}
$("#background").offset(working);
}, 10);
});
This does manage to move it somewhat but it doesn't seem to be exact and isn't really accounting for the offset of the #background element when it changes position.
So I'm guessing I should do everything relative to the Background image (which is around 1200w X 421h)
So to do that you would do something like this i'm guessing
var relativeOffset = {
top: boatOffset.top - backgroundElement.offset().top,
left: boatOffset.left - backgroundElement.offset().left
}
And I would in theory get the offsets of the sprite relative to the large background image as opposed to the mobile viewport. But then how would I go about moving the background?
Sorry if it's a simple question but it's the first time I've ever had to work with this kind of stuff so I'm a bit confused.

Infinite scrolling div glitching with images

I'm currently using the following javascript as shown below.
It's working well when I place just text within the div .image_scroll_3 but as soon as I insert images the scroll glitches and won't move past the top of the image.
Any advice would be much appreciated
JS
<script>
(function($, undefined) {
$.fn.loopScroll = function(p_options) {
var options = $.extend({
direction: "upwards",
speed: 60
}, p_options);
return this.each(function() {
var obj = $(this).find(".image_scroll_2");
var text_height = obj.find(".image_scroll_3").height();
var start_y, end_y;
if (options.direction == "downwards") {
start_y = -text_height;
end_y = 0;
} else if (options.direction == "upwards") {
start_y = 0;
end_y = -text_height;
}
var animate = function() {
// setup animation of specified block "obj"
// calculate distance of animation
var distance = Math.abs(end_y - parseInt(obj.css("top")));
//alert("animate " + obj.css("top") + "-> " + end_y + " " + distance);
//duration will be distance / speed
obj.animate(
{ top: end_y }, //scroll upwards
1500 * distance / options.speed,
"linear",
function() {
// scroll to start position
obj.css("top", start_y);
animate();
}
);
};
obj.find(".image_scroll_3").clone().appendTo(obj);
$(this).on("mouseout", function() {
obj.stop();
}).on("mouseout", function() {
animate(); // resume animation
});
obj.css("top", start_y);
animate(); // start animation
});
};
}(jQuery));
$("#example4").loopScroll({ speed: 700 });
</script>
I think the problem is that your text_height is calculated before the images are actually loaded inside your .image_scroll_3 elements. So you'll need to wait for the images to load.
Put your loopScroll call inside a $(window).load like so:
$(window).load(function(){
$('#example4').loopScroll({speed:700});
});
That massive glitch should now be gone as the fix above should have helped mitigate it.
However, there is still some unwanted jank / stutter (don't want to use the word glitch again, lets keep it reserved for the initial problem) in movement of all images if you notice and I am guessing that is probably because we are animating the whole thing too fast. Passing in speed like 100 or 200 resolves that but this is not really a solution because, ideally, you should be able to put in any speed value and it should just produce smooth animations out of it.
I am working on exactly the same thing but before that, I want to know if the above fix for the glitch helps you and we are finally done with it? Let me know.
Update:
Here is my version that I spoke of earlier, for your perusal.
Because all you are trying to do is loop images in a very linear fashion, I, for one, do not see the need to rely on animate() function of jQuery. There is requestAnimationFrame API that I have leveraged instead. In fact, in my demonstration below I have completely abandoned jQuery in favour of vanilla JavaScript only because I kept finding alternatives to pretty much everything we needed to do in this demo. But of course, this is also a very subjective matter; a taste thing; so if you want to go with jQuery, then by all means.
Another fundamental change I brought is rather than updating top values, I have resorted to updating translateY values.
Take a look at this jsFiddle and let me know if it fits your needs.
JavaScript code of which is as belows:
// [http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/]
window.requestAnimFrame=(function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(callback){window.setTimeout(callback,1000/60);};})();
var main=null;
var imageScroll2=null;
var imageScroll3=null;
var totalHeight=null;
var initY=null;
var destY=null;
var currY=null;
var increment=null;
var direction=null;
var UP=null;
var DOWN=null;
var isPlaying=null;
function init(){
main=document.getElementById('example4');
imageScroll2=main.getElementsByClassName('image_scroll_2')[0];
imageScroll3=main.getElementsByClassName('image_scroll_3')[0];
totalHeight=imageScroll3.clientHeight;
UP='upwards';
DOWN='downwards';
isPlaying=true;
direction=UP;
increment=10;
if(direction===DOWN){
initY= -totalHeight;
destY=0;
}else{
initY=0;
destY= -totalHeight;
}
currY=initY;
imageScroll2.appendChild(imageScroll3.cloneNode(true));
if(imageScroll2.addEventListener){
imageScroll2.addEventListener('mouseover',function(){isPlaying=false;},false);
imageScroll2.addEventListener('mouseout',function(){isPlaying=true;},false);
}else{
imageScroll2.attachEvent('onmouseover',function(){isPlaying=false;});
imageScroll2.attachEvent('onmouseout',function(){isPlaying=true;});
}
requestAnimFrame(render);
}
function render(){
if(isPlaying){
imageScroll2.style.transform='translate(0px,'+currY+'px)';
if(direction===DOWN){
currY+=increment;
if(currY>=destY){currY=initY;}
}else{
currY-=increment;
if(currY<=destY){currY=initY;}
}
}
requestAnimFrame(render);
}
//
init();

Is there any good way to determine the "actual content width" of a web page?

Here's what StackOverflow looks like on my (huge) work monitor:
That is a lot of white space on either side of the site's actual content.
I get that this is how a very large percentage of websites are designed—so I'm not singling out SO here—but that's actually exactly why I'm asking this question. I'm thinking it'd be really nice if I had some reliable way (say, via JavaScript) of determining the "actual" width of a website, which I could then use to write a quick script that would auto expand any site I'm browsing to fill the available width on my monitor. As it is, I find it absurd that sometimes I still squint before reading tiny text before realizing/remembering to zoom in to take advantage of my enormous screen.
Ahh... much better.
I suspect this is possible, at least to a reasonable degree via some heuristic, as my Android phone appears to do something a lot like this when I double-tap on the screen while browsing the web.
This will do something sorta like that. Though probably misses all kinds of edge cases.
// Assuming jQuery for simplicity
var drillIn = function(node) {
var max = 0;
var windowWidth = $(window).width();
var result = 0;
$(node).children().each(function() {
var $this = $(this);
if ($this.width() > max) {
max = $this.width();
}
});
if (0 < max && max < windowWidth) {
return max;
} else {
$(node).children().each(function() {
var childMax = drillIn(this);
if (childMax > result) {
result = childMax;
}
});
return result;
}
};
drillIn(document.body);
Working Fiddle: http://jsfiddle.net/bdL5b/1/
On SO, I get 960 which is right. Basically it drills into the DOM tree to find the widest node closest to the root which is not 0 or the window width. Because usually, close to the root node there is a container node which holds the site content. Usually.
Not sure you will get a 100% reliable solution though. This is a tricky thing because there are a TON of ways to style websites. I bet crazy stuff like horrible use of absolute positioning could be a serious thorn in your ass.
If you use Firefox, Greasemonkey is awesome. It will run Javascript that you write on any page (I have used it on Stack Overflow's site before).
Just use the browser's built-in "inspect element," to get the id of whatever you want to expand and do this:
document.getElementById("content").style.width = "100%"; // content is just an example
I think the class name of the middle boxes is .container so you could do this:
var boxes = document.getElementsByClassName("container");
for(var i = 0; i < boxes.length; i++)
{
boxes[i].style.width = "100%";
}
As far as a heuristic for doing this arbitrarily, there's probably no good way to do it to all web pages in an unbiased way, without significantly messing up the site's appearance.
That being said, this or something similar might work ok:
var divs = document.getElementsByTagName("div");
for(var i = 0; i < divs.length; i++)
{
divs[i].style.minWidth = "90%";
}
Ha! I've got something close (though I'm also going to try Alex's approach):
The following relies on jQuery and is arguably inefficient (it inspects, I believe, every element in the DOM); but it doesn't take any time on my machine and at least works with SO:
(function($) {
function text($element) {
return $.trim($element.clone().children().remove().end().text());
}
function hasContent($element) {
return $element.is(":visible") && text($element).length > 0;
}
function getExtremeEdges($elements) {
var extremeLeft = null;
var extremeRight = null;
$.each($elements, function(i, el) {
var $element = $(el);
var offset = $element.offset();
if (!extremeLeft || offset.left < extremeLeft) {
extremeLeft = offset.left;
}
if (!extremeRight || (offset.left + $element.width()) > extremeRight) {
extremeRight = offset.left + $element.width();
}
});
return [extremeLeft, extremeRight];
}
var $elementsWithContent = $("*").filter(function(i, el) {
return hasContent($(el));
});
var extremeEdges = getExtremeEdges($elementsWithContent);
var width = extremeEdges[1] - extremeEdges[0];
var desiredWidth = $(document).width() * 0.95;
if (width < desiredWidth) {
$("body").css("zoom", (desiredWidth / width));
}
}(jQuery));
Minified (to use as a bookmarklet):
(function(a){function b(b){return a.trim(b.clone().children().remove().end().text())}function c(a){return a.is(":visible")&&b(a).length>0}function d(b){var c=null;var d=null;a.each(b,function(b,e){var f=a(e);var g=f.offset();if(!c||g.left<c){c=g.left}if(!d||g.left+f.width()>d){d=g.left+f.width()}});return[c,d]}var e=a("*").filter(function(b,d){return c(a(d))});var f=d(e);var g=f[1]-f[0];var h=a(document).width()*.95;if(g<h){a("body").css("zoom",h/g)}})(jQuery);
Time to dogfood this puppy for a while...
I think each website will be too different to have a standard was of auto resizing their content. I belive CSS is the key, by using user defined style sheets. Or something like Stylish. See https://superuser.com/questions/128666/custom-per-site-stylesheet-extension-for-firefox
or https://addons.mozilla.org/en-us/firefox/addon/style-sheet-chooser-ii/
Not much progress but I'm putting what I tried up in case it inspires anyone else:
Works much worse than you would think
Make a bookmarklet that makes all children of body have 100% width. Then, if you click the bookmarklet again, it makes all children of children of body have 100% width. This way, the user can just click until the site becomes more pleasing to them :)
var levels = levels ? levels + 1 : 1;
$('body *:nth-child(' + levels + ')').css({ width: '100%' });
.
First approach to try and figure out where the first meaningful content is
Cool puzzle, I'm employing the awesomeness of jQuery. So I'm approaching it by trying to find the first element which has more non-empty .contents() than .children() because contents also fetches text nodes. Here's what I have so far. It's close, but not quite right because it seems to be searching a bit too deep:
$('body *:visible').filter(function(){
return moreNonEmptyContentThanChildren($(this));
}).first();
function moreNonEmptyContentThanChildren(el) {
var contentCount = 0;
var contents = el.contents();
for (c = 0; c < contents.length; c++) {
elc = contents[c];
if (elc.nodeType != 3 || (elc.nodeType == 3 && $.trim($(elc).text()) != '')) {
contentCount ++;
}
}
return contentCount != el.children().length;
}

How to let resize vertically a DIV with only jQuery - no plugins?

Edit: I put this snippet of code in jsbin: http://jsbin.com/eneru
I am trying to let the user resize (only vertically) a DIV element with jQuery. I read about jQuery UI, I tried it, and in some minutes, I had it working. But the library is adding a ~25KB overhead that I would like to avoid, since I only want simple vertical resizing.
So I tried to do it on my own. Here it is the HTML, I am using inline styling for clarity:
<div id="frame" style="border: 1px solid green; height: 350px">
<div style="height: 100%">Lorem ipsum blah blah</div>
<span id="frame-grip" style="display: block; width: 100%; height: 16px; background: gray"></span>
</div>
As you can see, there is a little bar under the DIV element, so the user can drag it up or down to resize the DIV. Here it is the Javascript code (using jQuery):
$(document).ready(function(){
var resizing = false;
var frame = $("#frame");
var origHeightFrame = frame.height();
var origPosYGrip = $("#frame-grip").offset().top;
var gripHeight = $("#frame-grip").height();
$("#frame-grip").mouseup(function(e) {
resizing = false;
});
$("#frame-grip").mousedown(function(e) {
resizing = true;
});
$("#frame-grip").mousemove(function(e) {
if(resizing) {
frame.height(e.pageY - origPosYGrip + origHeightFrame - gripHeight/2);
}
});
});
It works, more or less, but if you drag the bar too fast, it stops following the mouse movement and everything breaks.
It is the first time I try to do something serious (ahem) with JS and jQuery, so I may be doing something dumb. If so, please do tell me :)
You are doing something dumb: You're trying to do it yourself.
Hear me out, hear me out: Javascript across browsers is a horrible, horrible thing. There are many engines in many versions with many different operating systems, all of which have many subtleties, all of which make Javascript pretty much hell to work with. There is a perfectly good reason why librabries such as jQuery (and their extensions) have exploded in popularity: a lot of great programmers have spent a lot of hours abstracting all these horrible inconsistencies away so we don't have to worry about it.
Now, I am not sure about your user base, maybe you are catering to old housewives that still have dialup. But for the most part in this day and age the 25KB hit on the initial page load (as it will be cached afterwards) for the peace of mind that this is going to work in all browsers consistently is a small price to pay. There is no such thing as "simple" resizing when it comes to Javascript, so you're better off using UI.
I worked on a similar thing and managed to get it to work with maximum and minimum height and to me seems to work very fluid, this was my code.
$(document).ready(function()
{
var resizing = false;
var frame = $("#frame").height();
$(document).mouseup(function(event)
{
resizing = false;
frame = $("#frame").height();
});
$("#frame-grip").mousedown(function(event)
{
resizing = event.pageY;
});
$(document).mousemove(function(event)
{
if (resizing)
{
$("#frame").height(frame + resizing - event.pageY);
}
});
});
live example of how I used it, pull the red button, lacked images so i replaced with simple color. http://jsbin.com/ufuqo/23
I agree with Paolo about using UI, but here are some modifications to your code to get it working:
$(document).ready(function(){
var resizing = false;
var frame = $("#frame");
$(document).mouseup(function(e) {
resizing = false;
});
$("#frame-grip").mousedown(function(e) {
e.preventDefault();
resizing = true;
});
$(document).mousemove(function(e) {
if(resizing) {
var origHeightFrame = frame.height();
var origPosYGrip = $("#frame-grip").offset().top;
var gripHeight = $("#frame-grip").height();
frame.height(e.pageY - origPosYGrip + origHeightFrame - gripHeight/2);
}
});
});
You can save having a do-nothing handler called when you're not resizing, by only binding the mousemove function when you are actually dragging:
$(document).ready(function(){
var resizing = function(e) {
var frame = $("#frame");
var origHeightFrame = frame.height();
var origPosYGrip = $("#frame-grip").offset().top;
var gripHeight = $("#frame-grip").height();
frame.height(e.pageY - origPosYGrip + origHeightFrame - gripHeight/2);
return false;
}
var stopResizing = function(e) {
$(document).unbind("mouseover", resizing);
}
$("#frame-grip").mouseup(stopResizing);
$("#frame-grip").mousedown(function(e) {
e.preventDefault();
$(document).bind("mouseover", resizing).mouseup(stopResizing);
});
});
(sample at http://jsbin.com/ufuqo)

Categories

Resources