Scroll a div when hovering over a clipped item - javascript

This is a tricky problem to describe...I have a fixed height <div> on my page with a bunch of content items inside. Each item is a square <div>, floated left, so they fill in the area left to right and top to bottom. If there are too many items to fit in the view, then the content area will scroll (overflow-y: auto).
Forgive the ASCII art:
---------------------
| [ 1 ] [ 2 ] [ 3 ] |
| [ 4 ] [ 5 ] [ 6 ] |
| [ 7 ] [ 8 ] [ 9 ] |
---------------------
The thing is, the items inside don't fit perfectly in the area without the bottom row getting clipped. So what I want to do is somehow automatically scroll the view down when the user hovers over an item that's clipped off the bottom of the content area.
I can't figure out how I would go about determining whether a particular item is clipped or not.
Is this totally wacky? Or is there a logical method for doing this?

This is a very basic example.
http://jsfiddle.net/8Kb7N/
Essentially, each of your square divs would have an associate anchor inside with a unique name.
You want to set a hover event for each item that sets the window.location to the name of its anchor. This should let it navigate inside the area.

After first experimenting with #Geuis' method, I realized I was solving the wrong problem, because the last row of items isn't necessarily the same row that's getting clipped.
For example, say I have 12 items in a 3x4 grid: 3 items per row, 4 rows in total. Then say my container is only tall enough to show the first two rows and the top half of the third row. The last row is the fourth row, but the row that's getting clipped is the third row, assuming I'm scrolled to the top. Or, what if I scroll to the bottom of the container? Now the second row is getting clipped, and off the top rather than the bottom.
So I realized that rather than looking at the rows, I need to look at the particular item that's being hovered over and determine if that single item is being shown in full or not. If it is, do nothing; if it's not, scroll up or down depending on which end of the item is clipped.
Here's what I came up with. On hover:
var containerHeight = $container.height(),
itemHeight = $(this).height(),
itemOffset = Math.floor($(this).position().top),
itemVisible = containerHeight - itemOffset,
itemClip = itemHeight - itemVisible;
if (itemClip > 0){
$container.scrollTo('+=' + itemClip, 600);
} else if (itemOffset < 0){
$container.scrollTo('-=' + Math.abs(itemOffset), 600);
}
($container is defined elsewhere in my script as the containing div)
Line by line:
Get the height of the container that holds all the items
Get the height of the item being hovered
Get the distance from the top of the container to the top of the hovered item
Subtract the distance (line 3) from the height of the container (line 1)
Take the difference from line 4 and subtract it from the height of the item being hovered (line 2)
Now, this tells you two things:
If the result of line 3 is negative, the item is being clipped by that many pixels past the top of the container
If the result of line 5 is positive, the item is being clipped by that many pixels past the bottom of the container
Knowing this, you can then scroll the container in the correct direction and by the correct distance to reveal the whole item.
The actual scrolling itself requires the jQuery ScrollTo plugin in order to scroll up or down x number of pixels from the current scroll position (not from the top of the container, which is what jQuery's built-in .scrollTop() function does).
(ScrollTo does not take a negative number as a value, so in order to scroll up, you need to get the absolute value of itemOffset - hence Math.abs(itemOffset)).

Related

Change picture based on scroll position

I am trying to implement a script which changes images "every time" user scrolls down.
I read something about and I think the best practice is replace images once user reach a specific scroll position.
The website will have 3 main sections:
1) introduction: the core message + "instruction" to use;
2) animation: when user scrolls down, the animation will show. So every 10 pixel (or more/less) the image changes but the user keeps seeing the same section. It is a sort of GIF in which user has the control of the timing. It is useful in order to let the user able to see every drawing (or to go faster if they don't want to see all).
3) conclusion: last message + my contact.
Each section will have "100% of the device height" and "100% of the device lenght" (each device will have its own dimension). These numbers are just useful to let you understand.
In other words, the "animation" will follow this path:
1) first image at 0 pixel (from top, for example);
2) second image at 10 pixel (from top, for example) which replaces the first one;
3) third image at 20 pixel (from top, for example) which replaces the second one;
4) fourth image at 30 pixel (from top, for example) which replaces the third one;
ecc.
Do you know a way to implent this script?
I would fire an event every time the page is scrolled then get the position of the top of the target element, and then do my logic there. Here is a code sample:
// can be any target
$(body).scroll( function () {
// your even fired on scroll - get the offset of the closet parent element
// you will likely loop here
var position = $("elementYouWantToGetOffSetFor").position();
if(position.Top >= previousElementsTop) // guessing you need to check it against closest sibling
{
// then do your image swap here
$("yourtargetimage").src("pathtowherethisis");
}
});

Flickr-like script: Alter element height to make column width match end-to-end?

Does such a script exist?
Masonry and flexbox do not make columns match end to end, like Flickr does; and obviously so, because neither resize height.
I want to be able to take elements of any (relative) width, and have a script resize their height like Flickr .
Basically, take a container with 6 elements. Imagine they exist as 2 columns with 3 rows.
Now, if element #2 is a few pixels more narrow than the other 5, the top column will end a few pixels before the bottom column does. I don't want this to happen.

Telerik RadGrid scrollbar is offsetting the columns

I have a page with anywhere between 1 and 6 dynamically built iframes containing RadGrids in two columns on the page. I've managed to get a column by the name Document Number to line up in all of them, however if one of them contains more data then the space allowed it will scroll. This is expected and correct.
My issue is when the scrollbar does show it pushes all my columns left just a smidge in that grid, and now it's out of sync with the other grids. I've added a small column which I can dynamically display to push the other grids' columns to match, I just need to be able to detect/determine if a scroll bar is actually being displayed.
I found an old telerik post that suggests I use the scroll height vs the overflow height and if scroll height is larger then we know there's a scroll bar being displayed. My attempts to use the supplied javascript have shown me that the post is outdated and that GridDataDiv no longer exists.
Is there a new/updated way to detect the presence of a scrollbar? Alternatively, is there a better way to have my document number columns even regardless of scrollbar?
Compare the grid's client width and the scroll area width of the grid data:
var grid = document.getElementById("RadGrid1"),
scrollArea = document.getElementById("RadGrid1_GridData");
// ex. 171 (note no units included)
alert("grid.clientHeight: " + grid.clientHeight);
// ex. 300px (note the "px" units are included)
alert("scrollArea.style.height: " + scrollArea.style.height);
// Is the verticle scroll bar visible?
var vertIsVis = scrollArea.style.height.replace("px", "") > grid.clientHeight;

Slickgrid: Possible to scroll horizontally on grid while dragging column?

I'm working with Slickgrid to display a large data set which may be used with anywhere from a few to 50 columns. I need the ability for users to reorder the columns as they wish, which I am currently able to do but with some inconvenience. If I happen to be grabbing the very last column and moving it to the front of a grid with several horizontal window widths of columns, I have to drag/drop and manually scroll left before I get the column positioned where I want it.
Does anyone know if there's a way to force the grid to automatically scroll horizontally based on where I'm trying to drag a column (i.e. when I attempt to drag the column outside the current grid viewport)?
Find mouse pointer position where you want to scroll and apply scrolling by this method...
$('#myGrid').mousemove(function(e){ //#myGrid is id of div of grid container
var parentOffset = $(this).offset();
diffX = ( ( parentOffset.left + $('#myGrid').width() ) - e.pageX);
if (diffX < 59 && diffX > 17){ //change the minimum and maximum area where you want to scroll. mine requirement is 59 and 17. You can find your custom position by some alerting or console.log
$('.slick-viewport ').scrollLeft($('.slick-viewport ').scrollLeft() + 5);
}
});
I ended up solving this problem by creating a sortable list of the grid's column names outside of the grid. When the order of the column names changes, the columns displayed on the grid resets based on the new order by calling the function grid.setColumns().

adjusting for browser font width variations in jquery

I am writing a script that takes the items in the navigation bar, and stretches each row except the last to the width of the menu's container. The process is basically:
-Find the menu container width
-Iterate through each item, adding the .outerWidth(true) to a variable containing the current row width
-When the current row width becomes greater than or equal to the container width run a few tests
--subtract .outerWidth(true) from current row width and add .innerWidth().
--if row width is still greater than container width, move to the next row array, and add the current item as the first item in the row,
--if the row width is equal to or less than the container width, add the item as the last item of the current row, and move to the next row array.
Once the rows have been created, calculated the necessary padding to add to each element by finding the difference between the container width and the row width and following the following formula:
this.addedPadding = Math.floor( this.difference / ( this.items.length * 2) );
then calculate the leftover space by:
this.leftovers = this.difference - (this.addedPadding * 2 * this.items.length);
Then proceed to iterate through all items, adding the added padding. Then take leftovers, iterate it downwards by 2's, adding 1px of padding to each side of the first element, then second, third, and so on until leftovers is equal to 1 or 0. If it equals one, add one px of padding to the padding-right of the last item in the row.
Iterate through each row, and repeat the process.
Now, the problem is, different browsers render font slightly differently, so the numbers don't always add up perfectly. My current solution is to change the container width by the necessary adjustment by the browser so that the rows render correctly. This doesn't even have consistent results. For instance, on the site I'm working on, in Chrome, the homepage renders incorrectly at first, but (at least on my computer) if you refresh, it renders correctly.
What would be the correct way to address this without having to change the containerWidth based on browser and content? Is there a way?
For an example of the issue, visit http://development.rjhallsted.com/login_system/browsing/projects/insidemt/

Categories

Resources