Get position of table cell within overflow element - javascript

I want to get the position/offset of a table cell and then using this data I want to append and position a new element in the exact same position.
The code to achieve this is as follows:
function addBlock()
{
// get the cell position
var cellPosition = $('.item').position(),
cellPositionTop = cellPosition.top,
cellPositionLeft = cellPosition.left;
// append the overlay
var blockOverlay = $('<div class="blockOverlay"></div>').appendTo('.container').hide();
// set the overlay width and height to the same as the cell
blockOverlay.css({
'background-color':'blue',
'width': $('.item').outerWidth(),
'height': $('.item').outerHeight()
});
// position the overlay in the same place as the cell
blockOverlay.css({
'position': 'absolute',
'top': cellPositionTop,
'left': cellPositionLeft
});
// show the overlay
blockOverlay.show();
}
The table containing the cell is quite big and sits inside an overflowing element meaning that the table cell may be offscreen. If the above code is run without scrolling then it works fine, however if I scroll and then run it, the offset is incorrect. This is because even though I am using position() and not offset() it is getting the cell position relative to its parent (.container) at the time of calling the function, rather that its position regardless of the scroll position.
How can I solve this?
Here is a fiddle that shows the problem: https://jsfiddle.net/25e6qmnh/
Try clicking the button at various scroll positions and you will see that blue box only ever overlays the red cell when at the start position. It should ALWAYS overlay the red cell regardless of the scroll position.

You need to add $('.container').scrollLeft() to your cellPositionLeft, so the new line will look like this:
cellPositionLeft = cellPosition.left + $('.container').scrollLeft();
Your are not calculating the position with the scroll width, so you need to add it. You will also need to do the same with scrollTop(), but that will be left for you.
Here is a working example: https://jsfiddle.net/qorpucwq/

You can initialize the value of the element .item once and then it works fine.
function addBlock()
{
// get the cell position
var
cellPositionTop = cellPosition.top,
cellPositionLeft = cellPosition.left;
// append the overlay
var blockOverlay = $('<div class="blockOverlay"></div>').appendTo('.container').hide();
// set the overlay width and height to the same as the cell
blockOverlay.css({
'background-color':'blue',
'width': $('.item').outerWidth(),
'height': $('.item').outerHeight()
});
// position the overlay in the same place as the cell
blockOverlay.css({
'position': 'absolute',
'top': cellPositionTop,
'left': cellPositionLeft
});
// show the overlay
blockOverlay.show();
}
var cellPosition;
$(document).ready(function(){
cellPosition = $('.item').position();
$('.clickme').on('click', function(e){
e.preventDefault();
addBlock();
});
});
Here is the working fiddle.

Related

Erratic scrollbar using Jquery

This is the fiddle. https://jsfiddle.net/igor_g/ksjkpg0t/16/
My intention is to build a scrollbar on a strip of colors. The colors are taken from the text it is supposed to scroll. Basically, the strip is an overview of all the colors that are used in the text fonts. The text is generated dynamically and can be very large and very small. My intention is to make the scroller's size proportional and at the same time scroll properly. I have tried various combinations using jquery but I just can not seem to get the scroller to work the way I want. Sometimes, the scroller doesnt seem to point to the right text passage. How can this be fixed?
The jquery code is as follows:
/// here is our plugin declaration
(function ( $ ) {
$.fn.colorScroller = function( options ) {
var settings = $.extend({
replaceBlack: 'rgb(83, 84, 72)',
colorScrollClass: "color-map",
overlayClass: "overlay",
scrollSectionClass: "mapSection",
coloredTextClass: "passage"
}, options );
// assign this(the selector that is calling this function) to container
var container = this;
// getting the height of container
var containerHeight = container.outerHeight(true);
// creating overlay scrolling element
var $overlay = $('<div class="'+settings.overlayClass+'" ></div>')
//creating container for colored parts
var $colorScroll=$('<div class="'+settings.colorScrollClass+'" ></div>')
// appending colormap element after container in DOM
container.after($colorScroll);
// approximate total height of browser vertical scroll buttons
var browserScrollButtons = 26;
// setting height of colorscroll element to the height of container
$colorScroll.outerHeight(container.outerHeight()-browserScrollButtons );
var scrollerHandleMin = 31
// here we are calculating the total height of text elements of container
var totalHeight = 0;
container.children('.'+ settings.coloredTextClass).each(function(){
totalHeight = totalHeight + $(this).outerHeight(true);
});
// calculate height of text empty elements like br or <p></p>
var emptyHeight = 0;
container.children().not('.'+ settings.coloredTextClass).each(function(){
emptyHeight = emptyHeight + $(this).outerHeight(true);
});
// here we are calculating the ratio b/n total height of children of container and the height of color-scroll element
var ratio = totalHeight/$colorScroll.outerHeight();
// here we create a jquery object containing of small divs which will be colored, and associated with each passage div in container
var $mini = $('.'+settings.coloredTextClass, container).map(function(){
// getting the height of passage, setting the height of small div element by dividing by ratio
var heightPassage=$(this).outerHeight(true)/ratio+'px';
// getting the color of passage
var colorPassage=$(this).css('color');
// color change if color is black
if (colorPassage=='rgb(0, 0, 0)')
colorPassage = settings.replaceBlack;
var elem = $('<div class="'+settings.scrollSectionClass+'" style="height:'+heightPassage+'; background-color:'+colorPassage+'" ></div>').get(0)
// returning a jquery object element with class, height and color associated according to previous calculations
return elem
});
// get approximate height of browser scroll bar handle
var browserScrollBarHeight = (containerHeight*(containerHeight-browserScrollButtons ))/(totalHeight + emptyHeight )
browserScrollBarHeight = browserScrollBarHeight > scrollerHandleMin ? browserScrollBarHeight : scrollerHandleMin
// set overlay scroller height to browser scroll handle height
$overlay.outerHeight(browserScrollBarHeight);
var overlayHeight = $overlay.outerHeight();
// appending the minified elements into colorscroll element
$($mini).appendTo($colorScroll);
// appending overlay element into color-scroll element
$colorScroll.append($overlay);
// getting top position of container related to document top
var colorScrollTop = $colorScroll.offset().top+1+parseInt($colorScroll.css('margin-top').replace('px', ''))
// getting multiple to create algorithm for converting top positions
var k = (totalHeight + emptyHeight - containerHeight)/($colorScroll.innerHeight()-overlayHeight)
// attaching draggable to overlay scrolling element, so that it can be moved along color scroll element
$overlay.draggable({
// constrain movement to color-scroll element only
containment: "."+settings.colorScrollClass,
// what to do when overlay is dragged
drag: function() {
// getting top position of overlay related to document top
var top = $(this).offset().top;
container.animate({
// scroll container vertically to the point of overlay top (related to color-scroll element ) associated with text in container
scrollTop: (top-colorScrollTop)*k +'px'
}, 2)
},
});
/// when mouse on color-scroller unbind container scroll and enble draggable
/// when mouse leaves color-scroller bind container scroll and disable draggable
$colorScroll
.mouseenter(function() {
$overlay.draggable('enable')
container.off('scroll', scrollText)
})
.mouseleave(function() {
$overlay.draggable('disable')
container.on('scroll', scrollText)
});
// function triggered when container scrolled, basically scroll the overlay
function scrollText(){
$overlay.animate({
top: container.scrollTop()/k + 'px'
}, 1)
}
container.on('scroll', scrollText)
// when the color-scroll element is clicked
$colorScroll.on('click',function(e){
// calculate the position of click related to color-scroll itself
var topPosition = e.pageY-$(this).offset().top;
// and move overlay top to that position
$overlay.animate({
top: topPosition+'px'
}, 200)
// and scroll container to text associated with overlay top
container.animate({
scrollTop: (topPosition+overlayHeight)*ratio-containerHeight+'px'
}, 10)
})
return container;
};
}( jQuery ));
/// end plugin
$(document).ready(function() {
var passes = [0, 1, 2, 3, 4, 5, 6]
for (var i in passes) {
col = document.getElementById('pass' + i).style.color;
var element = document.createElement("section");
element.style.background = col;
document.getElementById("left").appendChild(element);
}
canvas = document.createElement("canvas");
canvas.id = 'canvas';
canvas.style = 'height:700px;width:50px;';
/// here we init plugin function
$('#document_content').colorScroller({replaceBlack: 'rgb(0,0,0)'});
/// the other option with defaults are :
// colorScrollClass: "color-map", css class of colored scrollbar
// overlayClass: "overlay", css class of the custom scrollbar
// scrollSectionClass: "mapSection", css class of the small colored sections in colored scroll bar
// coloredTextClass: "passage" css class of the original text part
///
});

Add class depending on top-position value

I have tooltips set on top of an image. When the user clicks one of these tooltips a content opens to reveal some info.
I'd like to slide open the content up or down, depending where the tooltip is positioned (absolute). So, I'm trying to get the "top"-value and if it's larger than 50, add a class and sort out the rest with CSS.
The problem is I'm always just getting the "top"-value of the first element. Now I tried to add an each function, which leaves me with what seems to be the average value of all the tooltips' top positions?
$( ".tooltip" ).each(function() {
var toppos = $(".tooltip").css("top");
if ( parseInt(toppos) >= 50 ) {
$(this).addClass('higher');
}
});
I'm either using each wrong, or each is not what I should be going for here...
Target the current tooltip instead of all tooltips:
$( ".tooltip" ).each(function() {
var toppos = $(this).css("top");// Use $(this) instead of $('.tooltip')
if ( parseInt(toppos) >= 50 ) {
$(this).addClass('higher');
}
});
You may also try offset().top instead of css('top'):
var toppos = $(this).offset().top;

jQuery animate div that is dynamically created

I have a div that is being created in one of six locations (columns) and I then want these newly created divs (.letter-block). It should create a new block each second and these blocks need to "fall" to the bottom of the container column div (or stop at the top of last block in that column so as to get the effect the blocks are stacking on top of each other, similar to Tetris). I can get the blocks to create but once created, they don't "fall" to the bottom of the container div.
$(document).ready(function(){
setInterval(newLetter, 1000)
function newLetter(){
var $randCol = $("#col" + (Math.floor(Math.random()*6) + 1));
$randCol.prepend("<div class='letter-block'></div>").animate({'bottom':'0'}, 500);
};
});
Your code:
var $randCol = $("#col" + (Math.floor(Math.random()*6) + 1));
$randCol.prepend("<div class='letter-block'></div>").animate({'bottom':'0'}, 500);
The element that is selected here is one of your six columns. You prepend the new <div>, but the column is still what is selected, so you are trying to animate the column instead of the new <div>. Then you need to calculate how many blocks you are sitting on top of. Count the number of blocks in the column and then multiply that by their height, that is you new bottom position. Try this code:
$(document).ready(function(){
setInterval(newLetter, 1000);
function newLetter(){
var $randCol = $("#col" + (Math.floor(Math.random()*6) + 1));
var $newDiv = $("<div class='letter-block'></div>");
$randCol.prepend($newDiv);
$(document).ready(function(){
var $oldBlocks = $randCol.find('.letter-block');
var yPos = '' + ($oldBlocks.length * $oldBlocks.first().outerHeight());
$newDiv.animate({
'bottom': yPos
}, 500);
});
};
});
Make sure that the new div is position: absolute or position: relative (probably absolute in your case) or directional properties like bottom won't work on it. CSS:
.letter-block {
position: absolute;
// other CSS
}

Cleaning up a SerialScroll Resize Function

Greeting's
I'am still relatively new to JavaScript and Jquery and I know there has got to be a better method than the one I'am using.
I'am working on a serialScroll implementation. There is a master scrollTo that controls the left/right movement of a number of slides. Each slide contains it's own implementation of a vertical serialScroll. I have the resize on the scrollTo working great and the resize on the vertical works but I can't figure an elegant method for ensuring that on resize the current position remains centered, My current method works but is very inefficient.
$(function(){
var $up = $('#sec1_nav a.up').hide();//up button -- each slide needs it's own unique nav buttons
var $down = $('#sec1_nav a.down');//down button -- each slide needs it's own unique nav buttons
$('#screen1').serialScroll({
target:'#section1',
items:'.item',
prev:'#sec1_nav a.up',
next:'#sec1_nav a.down',
axis:'y',
duration:1000,
force:true,
cylce: false,
onBefore:function( e, elem, $pane, $items, pos ){
$up.add($down).show();
if( pos == 0 )$up.hide();
else if( pos == $items.length -1 )
$down.hide();
// Here's where it get ugly, I'am adding a unique class for each slide to the item's
$('.item').removeClass('pos1'); //Each slides need's it's own class i.e. slide1 = pos1, slide2 = pos2 etc.
$(elem).addClass('pos1');
}
});
$(window).bind("resize", function(){
resize1(); // Same goes for the resize function, each slide need's it's own function.
});
});
function resize1() {
height = $(window).height();
width = $(window).width();
mask_height = height * $('.item').length; // sets the new mask height
// Resize Height of the area
$('.sections').css({height: height, width : width});
$('.item').css({height: height, width : width});
$('#mask').css({height : mask_height, width : width});
$('.sections').scrollTo('.pos1', 0 ); // This issue is where it all fall apart, instead of using serialScroll, i'am stuck using scrollTo to maintain the current slide position.
}

jQuery sliding table header

My ASP.Net application generates an <asp:Table> from the codebehind. What I need is for the header row of that table to slide down the page as the user scrolls past it.
I've tried the following approach using JavaScript:
window.onscroll = function () {
//grab the current scroll position
var scrollY = document.body.scrollTop;
if (scrollY == 0) {
if (window.pageYOffset)
scrollY = window.pageYOffset;
else
scrollY = (document.body.parentElement) ? document.body.parentElement.scrollTop : 0;
}
//grab the position of the header row I want to slide
var head = $("tr[name='headerrow']").offset();
var headtop = head.top;
var headleft = head.left;
//if the user has scrolled past the top of the header row
if (scrollY > headtop) {
//code correctly reaches this point as alerts show
//alert('got here');
//position the header row to the same as the scroll position
$("tr[name='headerrow']").offset({ top: scrollY, left: headleft });
}
}
I can't get the row to move. There are no error message to be seen on the various browsers developer tools.
Any help would be appreciated.
EDIT: I tried calling the offset() function on the children of the row (i.e. all of the <th> elements) like this:
$("tr[name='headerrow']").children().offset({ top: scrollY, left: headleft });
This now works but of course, they're all pushed over to the left because I'm using the left value of the header row itself... I'll keep this updated with my progress but in the meantime any assistance is appreciated as always.
Solution:
Use the children() method on the table row to allow you to change the offset of each of the <th> elements. The left value can be omitted from the offset() method, i.e.
$("tr[name='headerrow']").children().offset({ top: scrollY });
You cannot set the offset to any element. You should use css method and set the top and left parameters.

Categories

Resources