Access contents of div elements based on their window position - javascript

I have two div elements on my page which are positioned in such a way that both divs are at the same distance from the top of the page but are separated by some horizontal distance. Both div elements have some text entered into them dynamically using Javascript/jQuery. I want to access the text within the two divs in such a way that I can perform some action when both divs contain the same (or matching) text. Is there a way to do this based on the position of the divs using Javascript/jQuery ? I cannot use the obvious solution of id's because of certain restraints.

Lets say that the two divs you want are at 100, 100 and 100, 300 :
var all_divs = $("div");
var div1;
var div2;
for (var i=0; i<all_divs.length; i++){
var o = $(all_divs[i]).offset();
if (o.top == 100 && o.left == 100) {
div1 = all_divs[i];
}
if (o.top == 100 && o.left == 300) {
div2 = all_divs[i];
}
}
var polling = setInterval(function(){
if ($(div1).text() == $(div2).text()) {
perform_some_action();
clearInterval(polling);
}
}, 500);

If you're looking to identify your divs based on their position use .offset()
-Api documentation for .offset()

Related

NATIVE JavaScript only - element opacity change when scrolled into viewport

I'm trying to make the elements on the page fade in on scroll. Easy enough right? Not for me.
HTML is a standard list.
CSS sets all elements to opacity 0 prior to scrolling.
I'm trying to use Native JavaScript only.
// get current page body
var actBody = document.getElementById('acts-body');
// on scroll function
actBody.onscroll = function(){
// get screen height
var screenPosition = window.innerHeight;
// get all text elements
var artistName = document.getElementsByClassName('artist');
// loop through all elements
for(var i = 0; i < artistName.length; i++){
// get each elements position from top
var positionFromTop = artistName[i].getBoundingClientRect().top;
// if element is in viewport add class
if(positionFromTop - screenPosition <= 0){
artistName[i].classList.add('txt-fadeIn');
}
else{
artistName[i].classList.remove('txt-fadeIn');
}
console.log(artistName[i]);
}
i think it should solve it
if(screenPosition - positionFromTop <= 0){
artistName[i].classList.add('txt-fadeIn');
}

How to keep adding items to a div until both divs have same height?

I have two divs which are side by side. Currently, I display n+2 items in left div and n items in right one. n varies based on category and is predetermined. My problem is sometimes individual items in left div have more height than usual. How can I keep adding items to the right div until both divs have about same height?
Try this?
var $left_div = $('#left_div');
var $right_div = $('#right_div');
while($left_div.height() > $right_div.height()){
$right_div.append($your_item);
}
Where $your_item is defined as whatever you want to add onto your right div
Alternatively you can check for a threshold
var threshold = 200;
var $left_div = $('#left_div');
var $right_div = $('#right_div');
while(Math.abs($left_div.height() - $right_div.height()) < threshold){
$right_div.append($your_item);
}

JavaScript scrolling events, fade in place?

I'm trying to pin some divs in place and fade them in and out as a user scrolls down. My code looks like this so far:
$(window).on("load",function() {
var fadeDuration = 500;
function fade() {
// compute current window boundaries
var windowTop = $(window).scrollTop(),
windowBottom = windowTop + $(window).innerHeight(),
focusElt = null;
// find our focus element, the first visible .copy element,
// with a short-circuiting loop
$('.imgdiv').toArray().some(function(e, i) {
var objectTop = $(e).offset().top;
if ((objectTop >= windowTop) && (objectTop <= windowBottom)) {
focusElt = e;
return true;
}
console.log(focusElt);
});
// obscure all others
$('.focus').not(focusElt)
.removeClass('focus')
.fadeTo(fadeDuration, 0);
// focus on our focus element; if was the previous focus, nothing
// to do; but if it wasn't focus / wasn't showing before, make
// it visible and have class focus
$(focusElt).not('.focus')
.addClass('focus')
.fadeTo(fadeDuration, 1);
}
fade(); //Fade in completely visible elements during page-load
$(window).scroll(function() {fade();}); //Fade in elements during scroll
});
Here's the corresponding fiddle that almost does what I'm looking for, but instead of the green "Fade In" blocks moving upward and fading, I want them pined in place near the top of the window. As the "IMG DIVs" move past them they will fade and reappear with each new "IMG DIV". Here, I'm focusing on the particular green block and fading it when it becomes the focus element. Instead, what I need to do is, focus on the IMG DIV blocks, add a "pinned" class to the green blocks when they reach the top of the page, and fade the green blocks in and out.
Does anyone have any advice?
Part 2 of my question is how to do this with native JavaScript, and not rely on jQuery's dependency.
Ok, so lets split your first issue into two issues :)
First of all, you want to (in general) do something when some element becomes visible in the viewport and when it becomes invisible. So, basically, all you need is function like that:
watchElementIsInViewport(
$('.imgdiv'),
doSomethingWhenElementAppearedInViewport,
doSomethingWhenElementOutOfViewport
);
You know, that when element becomes visible, you want to show some other element. When element becomes invisible, you want to hide that related element. So now, define those two functions:
function doSomethingWhenElementAppearedInViewport(element) {
// retrieve text related with the element
var $copy = $(element).next('.copy');
// fade it in
$copy.fadeTo(500, 1);
}
function doSomethingWhenElementGotOutOfViewport(element) {
// retrieve text related with the element
var $copy = $(element).next('.copy');
// fade it out
$copy.fadeTo(500, 0);
}
What about watchElementIsInViewport? There is no magic inside, only logic you already created, but decoupled from showing of finding elements.
function watchElementIsInViewport($elements, elementAppearedInViewport, elementGotOutOfViewport) {
var currentlyVisible = [ ];
// retrieve positions once, assume it won't change during script is working
var positions = getVerticalBoundaries($elements);
function _scrollHandler() {
var viewportTop = window.scrollY;
var viewportBottom = viewportTop + window.innerHeight;
$elements.each(function(index, element) {
var elementPosition = positions[index];
/* if you wish to check if WHOLE element is in viewport
* var elementIsInViewport = (elementPosition.top >= viewportTop) &&
* (elementPosition.bottom <= viewportBottom);
*/
var elementIsInViewport = (elementPosition.top < viewportBottom) &&
(elementPosition.bottom > viewportTop);
var elementIndexInCurrentlyVisible = currentlyVisible.indexOf(element);
// if element is visible but was not visible before
if(elementIsInViewport && (elementIndexInCurrentlyVisible === -1)) {
elementAppearedInViewport(element);
currentlyVisible.push(element);
// if element is not visible but was visible before
} else if(!elementIsInViewport && (elementIndexInCurrentlyVisible !== -1)) {
elementGotOutOfViewport(element);
currentlyVisible.splice(elementIndexInCurrentlyVisible, 1);
}
});
}
// initial check & update
_scrollHandler();
// check & update on every scroll
$(window).on('scroll', _scrollHandler);
}
And that's all. Working example.

how to highlight a word given coordinates

I found this code: (result of the script):
HTML
<p>Each word will be wrapped in a span.</p><p>A second paragraph here.</p>Word: <span id="word"></span>
JAVASCRIPT
// wrap words in spans
$('p').each(function() {
var $this = $(this);
$this.html($this.text().replace(/\b(\w+)\b/g, "<span>$1</span>"));
});
// bind to each span
$('p span').hover(
function() { $('#word').text($(this).css('background-color','#ffff66').text()); },
function() { $('#word').text(''); $(this).css('background-color',''); }
);
I would like something similar. What I need to do is to obtain the same result but instead of highlighting the word (span tag) under the cursor I need to highlight a word (span tag) given the coordinates in pixels.
Does anyone know if this is possible and how can I do it? Or is there another way?
Thank you!
Maybe you want to use elementFromPoint(). It's really simple to use, you need to pass the coordinates and this function will return an element under the point.
For your particular case, every word must be in an independent element span, div or whatever.
See the working example: jsfiddle
Maybe you want to make some more robust solution, and add a condition if in the given coordinates there is not an element (elementFromPoint() return its ancestor or the body element or NULL if coordinates are not in visible part)
This is relatively easy once every word token is wrapped in a span. You can use jQuery's .position(), .width() and .height() functions to determine if an element overlaps with a given set of x,y coordinates.
Something as simple as
var x = 100, y = 100;
$("span.token").filter(function () {
var $this = $(this), pos = $this.position();
return y >= pos.top && y <= pos.top + $this.height() &&
x >= pos.left && x <= pos.left + $this.width();
})
finds the element(s) at position 100,100.
However. Your "wrap words in spans" function is wrong and potentially dangerous. It must be rewritten to a more complex, but in exchange safer approach.
I've created a .tokenize() jQuery plugin that walks the DOM tree and works on substitutes all text nodes it finds, wrapping them in a configurable bit of HTML:
$.fn.extend({
// this function recursively tokenizes all text nodes in an element
tokenize: function (wrapIn) {
return this.not(".tokenized").each(function () {
$(this).addClass("tokenized").children().tokenize(wrapIn);
$(this).contents().each(function () {
var node = this,
parent = this.parentNode,
tokens, tokenCount;
// text node: tokenize, dissolve into elements, remove original text node
if (node.nodeType === 3) {
tokens = $(node).text().replace(/\s+/g, " ").split(" ");
tokenCount = tokens.length;
$.each(tokens, function (i, token) {
if (token > "") {
parent.insertBefore($(wrapIn).text(token)[0], node);
}
if (i < tokenCount - 1) {
parent.insertBefore(document.createTextNode(" "), node);
}
});
parent.removeChild(node);
}
});
});
}
});
Usage:
$("p").tokenize("<span class='token'>");
See a live example here: http://jsfiddle.net/u5Lx6e2a/

How to find width of inner elements

I couldn't find any other questions asking the same thing, though that may be a problem with my search phrasing.
I'm trying to figure out how to find the largest width of all elements contained inside of a container div with a fixed width. So, in the image below, the black box is the container div with a fixed width. The red box represents the contents of the container div, which are subject to change. I want to find the width of the red box, using only the black box in js.
Here is a jsfiddle with what I've been working on/trying:
http://jsfiddle.net/w87k5/1/
the current jquery functions I've tried, with no success:
.width();
.innerWidth();
.outerWidth();
.scrollLeft();
Note: I do not know ANYTHING about the contents of this container. They could be any html element or mix of html elements, from divs to imgs to iframes. I could put a "red box" without a fixed width surrounding them. Overflow of the black box will be hidden.
Update: There could be any number of children in the container. Like this: http://jsfiddle.net/w87k5/3/
Update 2: I'm going to run benchmark speed tests on all of the answers to see which one is the fastest, and select one after that. Thanks for all your input!
Benchmarks:
I generated 1000 divs with a random width of inbetween 0 and 100, recorded the Date().getTime(), did the test, then recorded time again. Here are the results:
~2418 avg. milliseconds with the for loop for length. I might have messed this one up somehow?
for (var i = 1; i <= count; i++){
var q = $("#box :nth-child(" + i + ")").width();
if(q > box){
box = q;
}
}
~34.4 avg. ms for the .each loop.
~22.4 avg. ms for the .map function. (Chosen answer.)
If you need all nested elements can search with * selector which will return all descendent elements:
var widthArray=$('#box *').map(function(){
return $(this).outerWidth();
}).get();
var maxWIdth= Math.max.apply(Math, widthArray);
For just children:
var widthArray=$('#box').children().map(function(){....
You could use .each() to cycle though each child element.
jsFiddle example
var widths = [];
$('#box').children().each(function(i){
widths[i] = $(this).width();
});
alert(Math.max.apply(Math, widths));
Which will return the width of the child element with the largest width.
Get the number of children, and loop through to get the width of each
$(document).ready(function () {
var count = $("#box").children().length;
var h = 0;
for (var i = 1; i <= count; i++) {
max = $("#box :nth-child(" + i + ")").width();
var h = Math.max(max, h);
}
alert(h);
});
http://jsfiddle.net/JDVN3/1/
Please not that the index starts from 1 and not 0.
Check out: http://api.jquery.com/nth-child-selector/

Categories