Getting javascript to select ALL elements, not just the first one - javascript

I have copied a script which does some cool stuff with a floating tooltip (sticks to cursor and flips depending on which quadrant of the viewport it is in, to keep it visible at all times etc).
Everything works fine for the first element found. But it doesn't work on the second element, or any elements after that either.
// I want to select ALL divs with the class 'z-tooltip' but it only seems to select the first one
var tooltip = this.document.getElementsByClassName("z-tooltip")[0];
window.onmousemove = function(ev) {
var leftPixelSpace = ev.clientX;
var rightPixelSpace = this.innerWidth - leftPixelSpace;
var topPixelSpace = ev.clientY;
var bottomPixelSpace = this.innerHeight - topPixelSpace;
var tooltipPosX = leftPixelSpace > rightPixelSpace ? leftPixelSpace - tooltip.offsetWidth : leftPixelSpace;
var tooltipPosY = topPixelSpace > bottomPixelSpace ? topPixelSpace - tooltip.offsetHeight : topPixelSpace;
// I want to apply these styles to ALL divs with the class 'z-tooltip', but again, it only seems to work on the first div...
tooltip.style.left = tooltipPosX+"px";
tooltip.style.top = tooltipPosY+"px";
};
.z-tooltip {
width: 150px;
height: 100px;
border: 1px solid black;
background-color : lightblue;
text-align: center;
position: absolute
}
<div class="z-tooltip">floating tooltip</div>
<div class="z-tooltip">floating tooltip</div>
<div class="z-tooltip">floating tooltip</div>
I did some reading and I have seen that getElementsByClassName("z-tooltip")[0] returns them as an HTML collection, which is not what I want.
Instead I should use querySelectorAll('.z-tooltip) which would select all elements with the class z-tooltip. However when I use this none of the script works any more :(
Furthermore, I want to be able to apply a style (see end of snippet) to ALL elements with the class z-tooltip. I know that to do this I will need to 'loop through' all of them and apply the style. Here's what I've tried so far but it doesn't work:
for (var i=tooltip.length; i--;) {
tooltip.style.left = tooltipPosX+"px";
tooltip.style.top = tooltipPosY+"px";
}
Can anyone point out what I'm doing wrong here?

// I want to select ALL divs with the class 'z-tooltip' but it only seems to select the first one
var tooltip = this.document.getElementsByClassName("z-tooltip");
window.onmousemove = function(ev) {
var leftPixelSpace = ev.clientX;
var rightPixelSpace = this.innerWidth - leftPixelSpace;
var topPixelSpace = ev.clientY;
var bottomPixelSpace = this.innerHeight - topPixelSpace;
// I want to apply these styles to ALL divs with the class 'z-tooltip', but again, it only seems to work on the first div...
[...tooltip].forEach(tooltip => {
let tooltipPosX = leftPixelSpace > rightPixelSpace ? leftPixelSpace - tooltip.offsetWidth : leftPixelSpace;
let tooltipPosY = topPixelSpace > bottomPixelSpace ? topPixelSpace - tooltip.offsetHeight : topPixelSpace;
tooltip.style.left = tooltipPosX+"px";
tooltip.style.top = tooltipPosY+"px";
});
};
.z-tooltip {
width: 150px;
height: 100px;
border: 1px solid black;
background-color : lightblue;
text-align: center;
position: absolute
}
<div class="z-tooltip">floating tooltip</div>
<div class="z-tooltip">floating tooltip</div>
<div class="z-tooltip">floating tooltip</div>
Took the [0] off to get all the tooltips
Change the logic to [...tooltip].forEach to convert the result to an array that could then be looped over

Related

How to create a new element on cursor DOM

How would I be able to create a new element and have it placed right where the mouse/cursor is located?
I have some example code below:
<div id = "adivthing></div>
<script>
var newthing = document.createElement("input");
document.getElementById("adivthing").appendChild(newthing);
</script>
If you use either the position: fixed or position: absolute style properties on the newthing element, you can then use the left and top properties to move the element around the box.
If you get the mouse coordinates from your triggering event (e.g. click), you can add the appropriate left and top to your element.
Example below:
function createInput(event){
var newthing = document.createElement("input");
document.getElementById("adivthing").appendChild(newthing); // Your existing code
// get the coordinates of the mouse
var x = event.clientX; // get the horizontal coordinate
var y = event.clientY; // get the vertical coordinate
// position newthing using the coordinates
newthing.style.position = "fixed"; // fixes el relative to page. Could use absolute.
newthing.style.left = x + "px";
newthing.style.top = y + "px";
}
/* Optional - Making new things more obvious in the pen */
input{
height: 10px;
width: 50px;
background: red;
}
#adivthing{
height: 600px;
width: 600px;
background: blue;
}
<!-- Onclick event added to your existing markup -->
<div id="adivthing" onclick="createInput(event)"></div>

Is it possible to select all the element which is overflow a particular div and give it some CSS and place in some another div

I want to select all the element which is overflow a particular div and give it some CSS and place in some another div.
Like I have a div of height 400px and I am adding json data to it , if the content goes outside of this div I want to take all the outside content and place it to another div.
if(print_part.offsetHeight<print_part.scrollHeight)
{
var body=document.getElementById("body");
$("body").append(
'<page size="A4" id="A4Page" style="margin-top:0px;!important"><div class="main_Header"><h5>AMERICAN UNIVERSITY OF ANTIGUA</h5></div></page>'
);
}
Here you have a fast way to do it. This could be improved by for now I have no time. This is the idea behind this.
const e = document.getElementById('overflow');
if (e.scrollHeight - e.clientHeight > 0) {
const lineHeight = getLineHeight(e);
let allLines = e.innerHTML.match(/[^\r\n]+/g);
const linesToShow = Math.trunc(e.clientHeight / lineHeight);
const linesToMove = allLines.slice(linesToShow, allLines.length - 1);
const originalDivContent = allLines.slice(0, linesToShow - 1);
e.innerHTML = originalDivContent.join('\n');
const containerDivContent = linesToMove.join('\n');
const container = document.getElementById('container');
container.innerHTML = containerDivContent;
}
function getLineHeight(element) {
const clone = element.cloneNode();
clone.innerHTML = '<br>';
element.appendChild(clone);
singleLineHeight = clone.offsetHeight;
clone.innerHTML = '<br><br>';
doubleLineHeight = clone.offsetHeight;
element.removeChild(clone);
return doubleLineHeight - singleLineHeight;
}
.fix {
width: 200px;
max-height: 100px;
border: 1px solid red;
}
.container {
width: 200px;
border: 1px solid blue;
}
<div id="overflow" class="fix">
aaaaaaaaaaaaaa
aaaaaaaaaaaaa
aaaaaaaaaa
aaaaaaaaaaaaa
aaaaaaaaaaaaaaa
aaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaa
aaaaaaaaa
aaaaaaaaa
aaaaaa
aaaaaaaaaaa
aaaaaaaaa
</div>
<div id="container" class="container"></div>
Unfortunately that's not easy possible like you thought it.
You really have to take every of your content-items, find out their height. If parentSize < contentItemsTotal than put it to the other container.
Can you add some of your code, which you already have written?
Greetings

Filling div using letter-spacing

The problem I'm having is filling a div with text using letter-spacing. The main issue is, I don't know the width of the div.
First I was thinking using, text-align= justify, but since that I've been running in the dark and got no clue to how to solve this. I'm guessing some scripting magic might do the trick.
An imgur link giving you an idea what I mean:
<div id="container">
<h1>Sample</h1>
<p>Another even longer sample text</p>
</div>
Here is a link showcasing an example; JSfiddle.
Based the comment of the poster it seems JavaScript is no problem. Here's a possible approach to solve the problem with jQuery:
JSFiddle 1
function dynamicSpacing(full_query, parent_element) {
$(full_query).css('letter-spacing', 0);
var content = $(full_query).html();
var original = content;
content = content.replace(/(\w|\s)/g, '<span>$1</span>');
$(full_query).html(content);
var letter_width = 0;
var letters_count = 0;
$(full_query + ' span').each(function() {
letter_width += $(this).width();
letters_count++;
});
var h1_width = $(parent_element).width();
var spacing = (h1_width - letter_width) / (letters_count - 1);
$(full_query).html(original);
$(full_query).css('letter-spacing', spacing);
}
$(document).ready(function() {
// Initial
dynamicSpacing('#container h1', '#container');
// Refresh
$(window).resize(function() {
dynamicSpacing('#container h1', '#container');
});
});
Update
Small tweak for when the wrapper gets too small: JSFiddle 2
Another solution if you don't have to be semantic (because you will get many spans), I mean if you need only the visual result, is to use flexbox.
So you have your <div id="#myText">TEXT 1</div>
We need to get this:
<div id="#myText">
<span>T</span>
<span>E</span>
<span>X</span>
<span>T</span>
<span> </span>
<span>1</span>
</div>
So then you can apply CSS:
#myText {
display: flex;
flex-direction: row;
justify-content: space-between;
}
In order to transform the text to span you can use jQuery or whatever. Here with jQuery:
var words = $('#myText').text().split("");
$('#myText').empty();
$.each(words, function(i, v) {
if(v===' '){
$('#myText').append('<span> </span>');
} else {
$('#myText').append($("<span>").text(v));
}
});
For better results remove put letter-spacing: 0 into #myText so any extra spacing will be applied.
This is obviously evil, but since there is no straight forward way to do it with just css, you could do: demo
HTML:
<div>text</div>
CSS:
div, table {
background: yellow;
}
table {
width: 100%;
}
td {
text-align: center;
}
JS:
var text = jQuery("div").text();
var table = jQuery("<table><tr></tr></table>").get(0);
var row = table.rows[0];
for (var i = 0; i < text.length; i++) {
var cell = row.insertCell(-1);
jQuery(cell).text(text[i]);
}
jQuery("div").replaceWith(table);
This may help:
function fill(target) {
var elems = target.children();
$.each(elems, function(i,e) {
var x = 1;
var s = parseInt($(e).css('letter-spacing').replace('px',''));
while(x == 1) {
if($(e).width() <= target.width() - 10) {
s++;
$(e).css('letter-spacing', s+'px');
} else {
x = 0;
}
}
});
}
fill($('#test'));
Note: If letter spacing is : 0 then you don't have to use replace method. Or you can add letter-spacing:1px; to your css file.
For avoiding overflow, always give minus number to parent element's height for correct work.
An other approach I wrote for this question Stretch text to fit width of div. It calculates and aplies letter-spacing so the text uses the whole available space in it's container on page load and on window resize :
DEMO
HTML :
<div id="container">
<h1 class="stretch">Sample</h1>
<p class="stretch">Another even longer sample text</p>
</div>
jQuery :
$.fn.strech_text = function(){
var elmt = $(this),
cont_width = elmt.width(),
txt = elmt.text(),
one_line = $('<span class="stretch_it">' + txt + '</span>'),
nb_char = elmt.text().length,
spacing = cont_width/nb_char,
txt_width;
elmt.html(one_line);
txt_width = one_line.width();
if (txt_width < cont_width){
var char_width = txt_width/nb_char,
ltr_spacing = spacing - char_width + (spacing - char_width)/nb_char ;
one_line.css({'letter-spacing': ltr_spacing});
} else {
one_line.contents().unwrap();
elmt.addClass('justify');
}
};
$(document).ready(function () {
$('.stretch').each(function(){
$(this).strech_text();
});
$(window).resize(function () {
$('.stretch').each(function(){
$(this).strech_text();
});
});
});
CSS :
body {
padding: 130px;
}
#container {
width: 100%;
background: yellow;
}
.stretch_it{
white-space: nowrap;
}
.justify{
text-align:justify;
}

Strange behaviour of "position: relative" when zooming. What's happening?

The Fiddle: http://jsfiddle.net/4WFrJ/
My Problem:
I can't wrap my head around the behaviour of this setup.
When I zoom in, the images tend to move faster, but when I zoom out, they don't move at all. Sometimes they just stop at 9.xxxxxx, even though I told them to move only by one pixel. Can you explain this?
My browser is Chrome.
My Aim: achieve a fluid motion with the images disappearing when out of bounds of the parent element, whatever the magnification percentage.
I am in search of the basic rules, that govern these strange processes, from which I hope to learn new things.
The Code:
HTML:
<div id = "presentation">
<ul>
<li class = "pres-item"> <img class = "pres-image" src = "../img/presentation/image1.jpg"> </li>
<li class = "pres-item"> <img class = "pres-image" src = "../img/presentation/image2.jpg"> </li>
<li class = "pres-item"> <img class = "pres-image" src = "../img/presentation/image3.jpg"> </li>
<li class = "pres-item"> <img class = "pres-image" src = "../img/presentation/image4.jpg"> </li>
</ul>
</div>
CSS:
html, body {
margin: 0;
}
#presentation {
padding: 10px;
width: 900px;
margin: 50px auto;
overflow: hidden;
}
#presentation ul {
list-style-type: none;
margin: 0;
}
#presentation ul li {
display: inline-block;
}
.pres-item {
height: 150px;
width: auto;
position: relative;
left: 0;
}
.pres-image {
width: inherit;
height: inherit;
}
JS (with jQuery):
$(document).ready(function(){
var presentation = $('#presentation');
var interval = setInterval(function() {
console.log('intervaling');
$('.pres-item').css('left', '+=1');
}, 60);
});
The Image:
The Thanks:
THANKS PEOPLE (in advance)
<script>
// too much code, but it explains..
// do this in ur interval...
var getCurrent_left = $('.pres-item').css('left');
var newCurrent_left = getCurrent_left.split['px'];
var newCurrent_left = parseInt(newCurrent_left[0]) + 1;
var newCurrent_left = parseInt(newCurrent_left);
$('.pres-item').css({"left", newCurrent_left});
// you can use parseFloat(var, 2) for decimal
</script>
My Problem:
When I zoom in, the images tend to move faster, but when I zoom out, they don't move at all.
I'm not sure this is actually a problem. They appear to move slower when zoomed out because they travel fewer screen pixels for each viewport pixel.
Sometimes they just stop at 9.xxxxxx, even though I told them to move only by one pixel. Can you explain this?
Apparently Chrome does not always return that CSS property as an integer. You can see the same effect in this code:
var presentation = document.getElementById('presentation');
var items = presentation.getElementsByClassName('pres-item');
var interval = setInterval(function () {
[].forEach.call(items, function (x) {
var lastLeft = getComputedStyle(x, null).getPropertyValue('left');
console.log(lastLeft);
x.style.left = (parseFloat(lastLeft) + 1) + 'px';
})
}, 60);
I'm not sure if this is a problem or not. You could easily avoid it by keeping track of the offset in a separate variable and incrementing it during your loop instead of computing it from the element's current style.
var presentation = $('#presentation');
var left = 0;
var interval = setInterval(function() {
++left;
$('.pres-item').css('left', left + 'px');
}, 60);

DIV stick to top till pushed offscreen by next DIV

I am trying to get a similar effect to the Instagram timeline on a project I am doing. My HTML is:
<div class="item">
<div class="title">
<h1>Some title</h1>
<span>Time here</span>
</div>
<div class="content"></div>
</div>
Which is repeated many times down the page, and my CSS is:
* {
margin: 0;
padding: 0;
}
.item {
width: 100%;
background-color: red;
}
.item h1, span{
padding: 2px 0 5px 5px;
}
.item span{
display: inline;
}
.title {
background-color: blue;
}
.content {
height: 200px;
background-color: green;
}
What I want to happen is when a user scrolls, <div class="title"> sticks to the top when a user is scrolling, but when the next <div class="title"> comes up it 'pushes' the previous one off screen and then fixes it's self to the top.
Screenshots:
Picture 1 - Look at the two headers, one for withhearts the other for brenton_clarke.
Picture 2 - brenton_clarke's header has reached the bottom of withheart's
Picture 3 - brenton_clarke's header is pushing withheart's offscreen
Picture 4 - brenton_clarke's headers is now stuck to the top till pauloctavious pushes it off
My Fiddle
Can anyone give me some help with this?
With the link suggested below I was able to get it sort-of working, but not great: http://jsfiddle.net/reb6X/1/
Having modified the jQuery to use .html() rather than .text() it works not to badly now: http://jsfiddle.net/reb6X/2/
You might want to check out this jsfiddle.
http://jsfiddle.net/kennis/JTvFZ/
I think it could get you in the right direction.
// Index of the currently 'active' section
var activeCache = null;
// Actual rendered height of a header element
var cloneHeight = function(){
var $clone = $('<div class="clone"></div>').appendTo('body'),
cloneHeight = $clone.outerHeight();
$clone.remove();
return cloneHeight;
}();
// Top offsets of each header
var offsets = [];
// Figure out which section is 'active'
var activeHeaderIndex = function(){
var scrollTop = document.body.scrollTop;
for ( var i = 0; i < offsets.length; i++ )
if ( offsets[i] - cloneHeight > scrollTop )
return Math.max( i - 1, 0 );
}
// Build the 'offsets' array
$('.header').each(function(i, obj){
offsets.push( $(this).offset().top );
});
// Listen to scroll events
$(window).on('scroll', function(){
var active = activeHeaderIndex(),
scroll = document.body.scrollTop,
clone = $('.clone').length,
$active = $('.header').eq(active),
prevTitle = $('.header').eq(active - 1).text(),
title = $active.text(),
$fixed = $('.fixed');
// Hide fixed header
if ( offsets[active] > scroll ){
if ( !clone ){
$('.header').eq(0).hide();
$('<li class="clone">' + prevTitle + '</li>').insertBefore($active);
}
$fixed.hide();
// Show fixed header
} else {
if ( clone ){
$('.header').eq(0).show();
$('.clone').remove();
}
$fixed.show();
}
// If we're not changing headers, exit
if ( active == activeCache ) return;
// Update active index
activeCache = active;
// Remove old fixed header (if any)
$('.fixed').remove();
// Add a new fixed header
$fixed = $('<div class="fixed">' + title + '</div>').appendTo('body');
}).trigger('scroll');

Categories

Resources