Vary div height based on start-end points - javascript

I'm trying to make one vertical line what goes from start point (defined by
CSS) to end point (which I didn't define yet).
The idea is; the user scrolls and the line keeps like sticky and/or grows its height until the end point.
But I don't know which logic I should apply.
(Not-working) example: https://jsfiddle.net/uzegqn7f/
That line should go, for example, to the second image's top following the user's scroll position.
<div class="vertical-line line-1"></div>
<img src="https://dummyimage.com/900x300/000000/fff.jpg" alt="" class="line-1-start">
<div class="content"></div>
<img src="https://dummyimage.com/900x300/000000/fff.jpg" alt="" class="line-1-end">
.content {
height:1000px;
}
img {
max-width:100%;
height:auto;
}
.vertical-line {
display: block;
position: absolute;
background: #ee403d;
width: 4px;
height: 10px;
z-index: 999;
}
.line-1 {
margin-left:10%;
margin-top:100px;
}
var distance = $('.line-1-end').offset().top - $('.line-1-start').offset().top;
function line_animation(element,distance) {
$(window).scroll(function(){
element.css("height", distance+"px");
});
}
$(document).on('load resize', function() {
var line1 = $(".line-1");
line_animation(line1,distance);
});
NOTE:
The distance between the elements is not always the same, may vary in responsive.

Try this (comments in code):
var start = $('.line-1-start').offset().top, // get where line starts
end = $('.line-1-end').offset().top, // get where line ends
line = $('#line');
drawLine($(window).scrollTop()); // draw initial line
$(window).scroll(function(){
drawLine($(this).scrollTop()); // draw line on scroll
});
$(document).on('resize', function() { // reset top and bottom and redraw line on window resize
start = $('.line-1-start').offset().top;
end = $('.line-1-end').offset().top;
drawLine($(window).scrollTop());
});
function drawLine(currentPosition) {
if (currentPosition >= start && currentPosition <= end) {
var distance = currentPosition - start;
line.css("height", distance+"px");
} else {
line.css("height", 0);
}
}
Updated fiddle

i didn't get to finish it but it's nearly there if it helps. It dynamically will figure out the height and start/end positions, you might be able to finish it off, it's not calculating the end position quite right, bit of tweaking and it'll be ok though. Checkout the JSfiddle;
https://jsfiddle.net/x4jhLohs/2/
$(document).on('ready', function() {
$(window).scroll(function(){
handleVerticalLine();
});
function handleVerticalLine() {
// Loop through and grab all our Vertical Line Containers, each one will have a Start and an End selector.
$('.vertical-line-container').each(function() {
// Grab our start and end elements.
var $startElement = $( $( this ).data( 'line-start-selector' ) );
var $endElement = $( $( this ).data( 'line-end-selector' ) );
var $verticalLine = $( this ).find( $( '.vertical-line' ) );
if( $startElement.length && $endElement.length && $verticalLine.length ) {
var startElementTopOffsfet = $startElement.offset().top;
var endElementTopOffsfet = $endElement.offset().top + $endElement.height();
var startElementVerticalLineBegin = startElementTopOffsfet;
var endElementVerticalLineBegin = endElementTopOffsfet;
$verticalLine.css( 'top', startElementTopOffsfet + $startElement.height() );
var verticalLinePercentage = startElementVerticalLineBegin / endElementVerticalLineBegin * 100;
verticalLinePercentage += $(window).scrollTop();
$verticalLine.css('height', verticalLinePercentage )
}
});
}
});

Related

Add and Remove class on window scroll [duplicate]

So basically I'd like to remove the class from 'header' after the user scrolls down a little and add another class to change it's look.
Trying to figure out the simplest way of doing this but I can't make it work.
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll <= 500) {
$(".clearheader").removeClass("clearHeader").addClass("darkHeader");
}
}
CSS
.clearHeader{
height: 200px;
background-color: rgba(107,107,107,0.66);
position: fixed;
top:200;
width: 100%;
}
.darkHeader { height: 100px; }
.wrapper {
height:2000px;
}
HTML
<header class="clearHeader"> </header>
<div class="wrapper"> </div>
I'm sure I'm doing something very elementary wrong.
$(window).scroll(function() {
var scroll = $(window).scrollTop();
//>=, not <=
if (scroll >= 500) {
//clearHeader, not clearheader - caps H
$(".clearHeader").addClass("darkHeader");
}
}); //missing );
Fiddle
Also, by removing the clearHeader class, you're removing the position:fixed; from the element as well as the ability of re-selecting it through the $(".clearHeader") selector. I'd suggest not removing that class and adding a new CSS class on top of it for styling purposes.
And if you want to "reset" the class addition when the users scrolls back up:
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 500) {
$(".clearHeader").addClass("darkHeader");
} else {
$(".clearHeader").removeClass("darkHeader");
}
});
Fiddle
edit: Here's version caching the header selector - better performance as it won't query the DOM every time you scroll and you can safely remove/add any class to the header element without losing the reference:
$(function() {
//caches a jQuery object containing the header element
var header = $(".clearHeader");
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 500) {
header.removeClass('clearHeader').addClass("darkHeader");
} else {
header.removeClass("darkHeader").addClass('clearHeader');
}
});
});
Fiddle
Pure javascript
Here's javascript-only example of handling classes during scrolling.
const navbar = document.getElementById('navbar')
// OnScroll event handler
const onScroll = () => {
// Get scroll value
const scroll = document.documentElement.scrollTop
// If scroll value is more than 0 - add class
if (scroll > 0) {
navbar.classList.add("scrolled");
} else {
navbar.classList.remove("scrolled")
}
}
// Use the function
window.addEventListener('scroll', onScroll)
#navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
width: 100%;
height: 60px;
background-color: #89d0f7;
box-shadow: 0px 5px 0px rgba(0, 0, 0, 0);
transition: box-shadow 500ms;
}
#navbar.scrolled {
box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.25);
}
#content {
height: 3000px;
margin-top: 60px;
}
<!-- Optional - lodash library, used for throttlin onScroll handler-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
<header id="navbar"></header>
<div id="content"></div>
Some improvements
You'd probably want to throttle handling scroll events, more so as handler logic gets more complex, in that case throttle from lodash lib comes in handy.
And if you're doing spa, keep in mind that you need to clear event listeners with removeEventListener once they're not needed (eg during onDestroy lifecycle hook of your component, like destroyed() for Vue, or maybe return function of useEffect hook for React).
Example throttling with lodash:
// Throttling onScroll handler at 100ms with lodash
const throttledOnScroll = _.throttle(onScroll, 100, {})
// Use
window.addEventListener('scroll', throttledOnScroll)
Add some transition effect to it if you like:
http://jsbin.com/boreme/17/edit?html,css,js
.clearHeader {
height:50px;
background:lightblue;
position:fixed;
top:0;
left:0;
width:100%;
-webkit-transition: background 2s; /* For Safari 3.1 to 6.0 */
transition: background 2s;
}
.clearHeader.darkHeader {
background:#000;
}
Its my code
jQuery(document).ready(function(e) {
var WindowHeight = jQuery(window).height();
var load_element = 0;
//position of element
var scroll_position = jQuery('.product-bottom').offset().top;
var screen_height = jQuery(window).height();
var activation_offset = 0;
var max_scroll_height = jQuery('body').height() + screen_height;
var scroll_activation_point = scroll_position - (screen_height * activation_offset);
jQuery(window).on('scroll', function(e) {
var y_scroll_pos = window.pageYOffset;
var element_in_view = y_scroll_pos > scroll_activation_point;
var has_reached_bottom_of_page = max_scroll_height <= y_scroll_pos && !element_in_view;
if (element_in_view || has_reached_bottom_of_page) {
jQuery('.product-bottom').addClass("change");
} else {
jQuery('.product-bottom').removeClass("change");
}
});
});
Its working Fine
Is this value intended? if (scroll <= 500) { ... This means it's happening from 0 to 500, and not 500 and greater. In the original post you said "after the user scrolls down a little"
In a similar case, I wanted to avoid always calling addClass or removeClass due to performance issues. I've split the scroll handler function into two individual functions, used according to the current state. I also added a debounce functionality according to this article: https://developers.google.com/web/fundamentals/performance/rendering/debounce-your-input-handlers
var $header = jQuery( ".clearHeader" );
var appScroll = appScrollForward;
var appScrollPosition = 0;
var scheduledAnimationFrame = false;
function appScrollReverse() {
scheduledAnimationFrame = false;
if ( appScrollPosition > 500 )
return;
$header.removeClass( "darkHeader" );
appScroll = appScrollForward;
}
function appScrollForward() {
scheduledAnimationFrame = false;
if ( appScrollPosition < 500 )
return;
$header.addClass( "darkHeader" );
appScroll = appScrollReverse;
}
function appScrollHandler() {
appScrollPosition = window.pageYOffset;
if ( scheduledAnimationFrame )
return;
scheduledAnimationFrame = true;
requestAnimationFrame( appScroll );
}
jQuery( window ).scroll( appScrollHandler );
Maybe someone finds this helpful.
For Android mobile $(window).scroll(function() and $(document).scroll(function() may or may not work. So instead use the following.
jQuery(document.body).scroll(function() {
var scroll = jQuery(document.body).scrollTop();
if (scroll >= 300) {
//alert();
header.addClass("sticky");
} else {
header.removeClass('sticky');
}
});
This code worked for me. Hope it will help you.
This is based of of #shahzad-yousuf's answer, but I only needed to compress a menu when the user scrolled down. I used the reference point of the top container rolling "off screen" to initiate the "squish"
<script type="text/javascript">
$(document).ready(function (e) {
//position of element
var scroll_position = $('div.mainContainer').offset().top;
var scroll_activation_point = scroll_position;
$(window).on('scroll', function (e) {
var y_scroll_pos = window.pageYOffset;
var element_in_view = scroll_activation_point < y_scroll_pos;
if (element_in_view) {
$('body').addClass("toolbar-compressed ");
$('div.toolbar').addClass("toolbar-compressed ");
} else {
$('body').removeClass("toolbar-compressed ");
$('div.toolbar').removeClass("toolbar-compressed ");
}
});
}); </script>

How to reverse direction of moving div once it reaches side of screen?

I have an absolutely positioned div that uses the jQuery .animate function to move horizontally from the right to left of the screen.
My problem is that once the div reaches the far left side, it continues and eventually disappears from the screen. How do you make it so that once the div reaches the left side, it will reverse and start going to the right? (and then vice versa so that the right side won't continue going right, but goes left again once it reaches the end)
HTML:
<div class="container">
<div class="block"></div>
</div>
CSS:
.block {
float:right;
position:absolute;
right:100px;
width:100px;
height:100px;
background:red;
}
jQuery:
$('.block').click(function() {
$(this).animate(
{"right": "+=100px"},"slow");
});
Here is my JSFiddle: https://jsfiddle.net/ebkc9dzL/
Thank you I really appreciate the help!
may be you should try like this:
$('.block').click(function() {
var leftPosition = $(this).position();
if (leftPosition.left > 100) {
$(this).animate({"right": "+=100px"},"slow");
} else {
$(this).animate({"right": "-=100px"},"slow");
}
});
when the element is close to the border the if..else part of the code will reverse the direction.
Here is a fiddle, try to click on the red box to get an idea on how it works:
https://jsfiddle.net/dimitrioglo/ebkc9dzL/14/
Working fiddle: https://jsfiddle.net/ebkc9dzL/19/
You need to have a variable outside the click function that will tell you the direction of the animation, so that once inside the click function you can calculate the location of the animated object using getBoundingClientRect() (mdn reference).
Then, if object is moving left and its left distance is less than its own width, you need to move it only enough so that it comes to the edge. If it's AT the edge (left is zero), you need to change the direction.
If it's moving right and its right distance is less than its own width, you need to move it only enough (calculated by window.innerWidth - 100, since 100 is width of your object) so that it comes to the edge. If it's AT the right edge, you need to change direction.
Changing direction in object you pass to jQuery's animate function is a simple matter of adding or subtracting from its "right" attribute.
var direction = "+";
$('.block').click(function() {
var obj = {},
distance = 100,
rect = this.getBoundingClientRect();
if(direction=="+"){
if(rect.left>0 && rect.left < 100)
distance = rect.left;
else if(rect.left<=0)
direction = "-";
}
else {
if(rect.right >(window.innerWidth-100) && rect.right+1<window.innerWidth)
distance = (window.innerWidth-rect.right);
else if(rect.right+1 >=window.innerWidth){
direction = "+";
}
}
obj = {"right": direction+"="+distance.toString()+"px"}
$(this).animate(obj,"slow");
});
Here you go: jsFiddle.
The new javascript is as follows:
var goLeft = true;
$('.block').click(function() {
var animateDist = 100;
var distLeft = $(this).position().left;
var distRight = window.innerWidth - distLeft;
if (goLeft) {
if (distLeft < 100) {
animateDist = "+="+distLeft+"px";
$(this).animate(
{"right": animateDist},"slow"
);
goLeft = false;
} else {
$(this).animate(
{"right": "+=100px"},"slow"
);
}
} else {
if (distRight < 100) {
animateDist = "-="+distRight+"px";
$(this).animate(
{"right": animateDist},"slow"
);
goLeft = true;
} else {
$(this).animate(
{"right": "-=100px"},"slow"
);
}
}
});
This isn't perfect, you need to adjust your internal window width to match the parent container, but this is enough to get you in the right direction.
Good luck!
Try this code:
var sign = [ "+" , "-" ];
var signPosition = 0;
var maxOffset = $(".block").offset().left;
$('.block').click(function() {
if ($(this).offset().left < 100) {
signPosition = 1;
} else if ($(this).offset().left == maxOffset) {
signPosition = 0;
}
$(this).animate(
{"right": sign[signPosition] + "=100px"},"slow");
});
The variable sign is the array that contains the directions in which the element might move, the variable signPosition contains the position of the direction currently in use, the variable maxOffset contains the starting position.
Hope this will help you.

jQuery TouchSwipe horizontal scrolling keeps going to start

I'm using jQuery TouchSwipe to make some horizontal, scrollable divs on a mobile site. I've got it set up so that the div scrolls left or right, depending on how you swipe. My problem lies within after you stop swiping and go to swipe again. When you go to swipe, the div goes back to the beginning. Obviously I want the div to stay where it's at and scroll from that position. Here is what I have so far.
$('#table_set').swipe({
swipeStatus:swipe1, allowPageScroll:'horizontal'
});
function swipe1(event, phase, direction, distance, duration){
if(direction == 'left'{
$(this).scrollLeft(distance);
}else{
$(this).scrollLeft('-' + distance);
}
}
I understand why it's going to the beginning of the div. Every time that you touch, duration equals 0. I just don't know what the next steps are. Any help would be amazing. Thanks!
I've created a demo of the swiping. I think the issue with going to the beginning of the div was because direction returns null if there was just a click and no swiping.
I've avoided this by exiting the callback if direction is null.
I'm not sure why you need the swiping at all because the scrolling works with-out touchSwipe.
Please finde the demo below and here at jsFiddle.
var IMAGECOUNT = 10;
var url = 'http://lorempixel.com/400/200';
var imgArr = [];
var loadCounter = 10;
var decCounter = function(){
loadCounter--;
if (!loadCounter) $("#table_set").trigger('allImgLoaded');
};
$(function() {
var $table = $('#table_set');
var img;
//init table set with dummy images
for(var i=0; i< IMAGECOUNT; i++){
imgArr[i] = new Image();
imgArr[i].src = url + '?' + (new Date()).getTime(); // add time to avoid caching
imgArr[i].onload = decCounter;
}
$("#table_set").on('allImgLoaded', function() {
//console.log(imgArr);
$table.append(imgArr);
});
});
$('#table_set').swipe({
swipeStatus:swipe1, allowPageScroll:'horizontal'
});
function swipe1(event, phase, direction, distance, duration){
console.log('swiped!', direction, distance, duration);
if ( direction === null ) return; // no swipe
var curPos = $(this).scrollLeft();
var newPos = curPos;
if(direction == 'left'){
newPos += distance;
$(this).scrollLeft(newPos);
}else{
newPos -= distance;
$(this).scrollLeft(newPos);
}
}
#table_set {
height: 210px;
width: 100%;
overflow-x: scroll;
overflow-y: hidden;
white-space: nowrap;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.touchswipe/1.6.4/jquery.touchSwipe.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="table_set">
</div>

jQuery resize of images [duplicate]

This question already has answers here:
Image resize of items jQuery
(2 answers)
Closed 10 years ago.
I have managed to fit automatically the images of the gallery per row depending if it´s horizontal (one image per row) or vertical (two images per row).
The problem now is that I want the images to be scalable (resize on window resize) but I have no idea how to achieve it. How it should me made? (I'm looking for a javascript/jquery solution to avoid height: auto problems...)
This is the web: http://ldlocal.web44.net/test2/gallery.html
Can be downloaded here: http://ldlocal.web44.net/test2/test.zip
this is my code:
var gallery = new Gallery($('#gallery_images_inner'));
function Gallery(selector){
this.add_module = function(type, image){
var container = $('<div />' , {
'class' : 'gallery_container'
}).append(image);
if(type == 'horizontal'){
var h_ar = image.attr('height') / image.attr('width');
container.css({
'width' : selector.width(),
'height' : selector.width()*h_ar
})
}
if(type == 'vertical'){
container.css({
'width' : v_width,
'height' : v_height
})
}
container.appendTo(selector);
container.children('img').fitToBox();
}
var _this = this;
var gutter = 0;
// start vars for counting on vertical images
var v_counter = 0;
var w_pxls = 0;
var h_pxls = 0;
// iterates through images looking for verticals
selector.children('img').each(function(){
if($(this).attr('width') < $(this).attr('height')){
v_counter++;
h_pxls += $(this).attr('height');
w_pxls += $(this).attr('width');
}
})
// calculates average ar for vertical images (anything outside from aspect ratio will be croped)
var h_avrg = Math.floor(h_pxls/v_counter);
var w_avrg = Math.floor(w_pxls/v_counter);
var v_ar = h_avrg/w_avrg;
var v_width = (selector.width())/2;
var v_height = v_width*v_ar;
selector.children('img').each(function(){
if(parseInt($(this).attr('width')) > parseInt($(this).attr('height'))){
_this.add_module('horizontal', $(this));
}else{
_this.add_module('vertical', $(this));
}
})
selector.isotope({
masonry: {
columnWidth: selector.width() / 2
}
});
}
Update ALL NEW CODE:
http://jsfiddle.net/vYGGN/
HTML:
<div id="content">
<img class="fluidimage" src="http://thedoghousediaries.com/comics/uncategorized/2011-04-06-1b32832.png"
/>
</div>
CSS:
body {
text-align:center;
}
img {
float: right;
margin: 0px 10px 10px 10px;
}
#content {
width:70%;
margin: 0px auto;
text-align: left;
}
JS:
$(document).ready(function () {
function imageresize() {
var contentwidth = $('#content').width();
if ((contentwidth) < '300') {
$('.fluidimage').attr('height', '300px');
} else {
$('.fluidimage').attr('height', '600px');
}
}
imageresize(); //Triggers when document first loads
$(window).bind("resize", function () { //Adjusts image when browser resized
imageresize();
});
});
Found this at this article:
http://buildinternet.com/2009/07/quick-tip-resizing-images-based-on-browser-window-size/
If you want to resize images automatically and scale them down proportionally, all you have to do is set a css max-width on the <img> tag. You can scale it down automatically with a percentage value according to the $(window) or any element in the document. Here's an example of how to scale it proportionally using the $(window) to a percentage of the window:
$(document).ready(function() {
$(window).resize(function() {
var xWidth = $(window).width();
$('.[img class]').each(function() {
$(this).css({maxWidth: xWidth * ([your percentage value of window] / 100)});
});
}).trigger('resize');
});
Change [img class] to the class of the images.
Change [your percentage value of window] to the percent of the window element you want your images width to be scaled at. So, if you want 90%, change this to 90. When the user resizes the browser window, it will automatically resize the images accordingly as well.

Why does an element start its css3 transition/transform from the top left of the window?

This is a bit annoying: i have a div which starts its transition from the top left of the window even when positioned anywhere else on the document. I've tried usign -webkit-transform-origin with no success, maybe i've used it wrong.
Could anybody help me? :)
Here's the code... all of it, but i've commented on the relevant parts - which are at the bottom, mainly.
Here's a live version of the code.
<style>
#pool{
width:100%;
}
.clickable{
<!-- class of the element being transitioned -->
display:inline;
margin-right: 5px;
-webkit-transition: all 500ms ease;
position: absolute;
}
.profile_image{
border: solid 1px black;
-webkit-transition: all 500ms ease;
position:relative;
}
</style>
<section id="pool"></section>
<script>
var Cache = {};
Cache.hasItem = function(item_key){
if(!localStorage.getItem(item_key)){
return false;
}else{
return true;
}
}
Cache.storeItem = function(key, value){
localStorage.setItem(key, value);
}
Cache.fetch = function(key){
return jQuery.parseJSON(localStorage.getItem(key));
}
Cache.clear = function(key){
localStorage.removeItem(key);
}
var Twitter = {};
Twitter.url = "http://api.twitter.com/1/statuses/public_timeline.json?callback=?";
Twitter.getFeed = function(){
console.log("Fetching...");
$.getJSON(Twitter.url, function(json){
Cache.storeItem('feed',JSON.stringify(json));
})
.complete(function(){
//to be implemented
console.log("Completed");
})
}
if(!Cache.hasItem('feed')){
Twitter.getFeed();
}
var feed = Cache.fetch('feed');
for(var i in feed){
var entry = feed[i];
var element = '<div id="'+i+'" class="clickable"><img class="profile_image" src="'+entry.user.profile_image_url+'"/></div>';
$("#pool").append(element);
}
</script>
<script>
$(".profile_image").click(function(e){
var target = $(e.target);
var parent = target.parent();
var windowWidth = $(window).width();
var windowHeight = $(window).height();
var newWidth = 500;
var newHeight = 100;
var newX = (windowWidth-newWidth)/2;
var newY = (windowHeight-newHeight)/3;
/************HERE'S THE PROBLEM*******/
parent.css('background-color','red');
parent.css('display','inline');
parent.css('position','fixed'); // tried absolute and inherit as well
parent.css('z-index','3');
parent.width(newWidth).height(newHeight).offset({top:newY, left:newX});
})
</script>
Results:
With help from jfriend00 i managed to fix it. Here's the code:
<style>
#pool{
width:100%;
display: inline;
}
.clickable{
display: inline-block;
margin-right: 5px;
position: scroll;
}
.profile_image{
border: solid 1px black;
}
</style>
And the Javascript:
<script>
$(".profile_image").click(function(e){
var target = $(e.target);
var parent = target.parent();
targetOffset = target.offset();
parentOffset = parent.offset();
target.css('top',targetOffset.top-5);
target.css('left',targetOffset.left-5);
parent.css('top',parentOffset.top);
parent.css('left',parentOffset.left);
var windowWidth = $(window).width();
var windowHeight = $(window).height();
var newWidth = 500;
var newHeight = 100;
var newX = (windowWidth-newWidth)/2;
var newY = (windowHeight-newHeight)/3;
parent.css('-webkit-transition', 'all 500ms ease');
parent.css('background-color','red');
parent.css('position','absolute');
parent.css('z-index','3');
parent.width(newWidth).height(newHeight).offset({top:newY, left:newX});
})
</script>
It looks to me like you change the object's position from relative to fixed upon the click (along with a few other style changes). When you change it to fixed, the object is no longer positioned in the flow of the page and it goes to it's left and top position on the page which it does not look like you've initialized - thus they are set to (0,0) so that's where the object jumps to when you change it's position to fixed (top/left of the page).
If you want them to transition from where they were, you will have to calculate their original position on the page and set top and left to those values in the same code where you set the position to fixed.
I would assume that jQuery has a function to calculate the object's absolute position in the page for you so you can use that (YUI has such a function so I assume jQuery probably does too). Since you're using "fixed", you may have to correct that for scroll position or use "absolute" instead of "fixed". One challenge here is you need to change the position and top/left without them being subject to a CSS transition because you want those attributes to change immediately. Then, you enable the transitions and set the final position.

Categories