CSS transition not working for right most div on offsetLeft - javascript

I have five divs. Four of those divs you can click, which will run a function that moves the div you clicked on to the coordinate of the fifth div using div.offsetLeft and div.offsetTop. The first three divs all work fine, but if you click the right most div first, the transition effect isn't applied while moving to the coordinates. If you click any of the other divs first, and then the right most div, the transition will apply.
If you make it so there are only two or three divs, the problem still persists. (You must remove the corresponding id from the parties array, as well as the html element).
jsfiddle: https://jsfiddle.net/zjystr2u/
Apologies for the javascript in the html. Have never used jsfiddle, and couldn't figure out how to make it load the javascript after the html.

Something janky is going on when you getCurrentPosAll() changes position from the default static to absolute
You could run getCurrentPosAll() before changing the top and left to set their default values correctly.
var selected = document.getElementById("selected");
var selectedX = selected.offsetLeft;
var selectedY = selected.offsetTop;
parties = ['opt1', 'opt2', 'opt3', 'opt4'];
getCurrentPosAll(); // (NEW) Make sure their defaults are set.
function moreTest(e) {
var party = e.target
party.style.left = selectedX + "px";
party.style.top = selectedY + "px";
}
function getCurrentPosAll() {
for (var idx = 0; idx < parties.length; idx++) {
var currentDiv = document.getElementById(parties[idx]);
var x = currentDiv.offsetLeft;
var y = currentDiv.offsetTop;
currentDiv.style.left = x + "px";
currentDiv.style.top = y + "px";
}
for (var idx = 0; idx < parties.length; idx++) {
var currentDiv = document.getElementById(parties[idx]);
currentDiv.style.position = "absolute";
}
}
.wrapper {
display: flex;
justify-content: space-around;
width: 75%;
margin: 0 auto;
}
.selected {
width: 100px;
height: 150px;
position: absolute;
left: 0;
right: 0;
margin-left: auto;
margin-right: auto;
background-color: black;
opacity: 0.6;
z-index: 1;
}
.opt {
width: 100px;
height: 150px;
cursor: pointer;
transition: top 0.7s, left 0.7s;
}
.opt1 {
background-color: red;
}
.opt2 {
background-color: blue;
}
.opt3 {
background-color: orange;
}
.opt4 {
background-color: green;
}
<div class="wrapper">
<div class="selected" id="selected"></div>
<div class="opt opt1" id="opt1" onclick="moreTest(event)"></div>
<div class="opt opt2" id="opt2" onclick="moreTest(event)"></div>
<div class="opt opt3" id="opt3" onclick="moreTest(event)"></div>
<div class="opt opt4" id="opt4" onclick="moreTest(event)"></div>
</div>
I'm not sure why it behaves like this. I figure it has to do with how and when the browser calculates the initial value for the transition. where last elements CSS changes get batched into 1 update.
therefor it will immediately receive the updated top and left values, whereas the other elements will receive 2 updates, one with the default top and left and then one with the updated values. causing their transition to work properly.
Most likely because the the last elements CSS is changed, their css updates are applied in 2 updates instead of 1.

var selected = document.getElementById("selected");
var selectedX = selected.offsetLeft;
var selectedY = selected.offsetTop;
parties = ['opt1', 'opt2', 'opt3', 'opt4', 'opt5','opt6'];
function moreTest(e) {
var party = e.target
getCurrentPosAll();
party.style.left = selectedX + "px";
party.style.top = selectedY + "px";
}
function getCurrentPosAll() {
for (var idx = 0; idx < parties.length; idx++) {
var currentDiv = document.getElementById(parties[idx]);
var x = currentDiv.offsetLeft;
var y = currentDiv.offsetTop;
currentDiv.style.left = x + "px";
currentDiv.style.top = y + "px";
}
for (var idx = 0; idx < parties.length; idx++) {
var currentDiv = document.getElementById(parties[idx]);
currentDiv.style.position = "absolute";
}
}
.wrapper {
display: flex;
justify-content: space-around;
width: 100%;
margin: 0 auto;
}
.selected {
width: 100px;
height: 150px;
position: absolute;
left: 0;
right: 0;
margin-left: auto;
margin-right: auto;
background-color: black;
opacity: 0.6;
z-index: 1;
}
.opt {
width: 100px;
height: 150px;
cursor: pointer;
transition: 0.7s;
}
.opt1 {
background-color: red;
}
.opt2 {
background-color: blue;
}
.opt3 {
background-color: orange;
}
.opt4 {
background-color: green;
}
.opt5 {
background-color: violet;
}
.opt6 {
background-color: black;
}
<div class="wrapper">
<div class="selected" id="selected"></div>
<div class="opt opt1" id="opt1" onclick="moreTest(event)"></div>
<div class="opt opt2" id="opt2" onclick="moreTest(event)"></div>
<div class="opt opt3" id="opt3" onclick="moreTest(event)"></div>
<div class="opt opt4" id="opt4" onclick="moreTest(event)"></div>
<div class="opt opt5" id="opt5" onclick="moreTest(event)"></div>
<div class="opt opt6" id="opt6" onclick="moreTest(event)"></div>
</div>

Related

Javascript scroll event listener only scrolls down once

I have set a scroll event listener on the document body to transform 100vh either up or down. This seems to work great on the first scroll down of 100vh and i can scroll back up 100vh to the start point as well. It doesn't seem to work though if i want to scroll down more than once. My markup is wrong some where but being fairly new to javascript i am struggling to see where i have gone wrong.
document.addEventListener('scroll', function() {
var previousScrollPos = 0;
var currentScrollPos = window.pageYOffset;
var nextScrollPos = 0;
if (currentScrollPos > previousScrollPos) {
nextScrollPos = nextScrollPos - 100;
document.body.style.transform = "translateY(" + nextScrollPos + "vh)";
} else {
nextScrollPos = nextScrollPos + 100;
document.body.style.transform = "translateY(" + previousScrollPos + "vh)";
}
});
body {
width: 100%;
height: 100%;
transition: all 1s;
color: black;
}
.section {
height: 100vh;
text-align: center;
line-height: 100vh;
}
.section1 {
background-color: white;
}
.section2 {
background-color: green;
}
.section3 {
background-color: red;
}
.section4 {
background-color: yellow;
}
<div class="section section1">1</div>
<div class="section section2">2</div>
<div class="section section3">3</div>
<div class="section section4">4</div>

Adapt image movement to window size in javascript

I made an animation on my website which moves if clicked on. The problem is that on the javascript function that manage it, I gave a series of coordinates which fits only if the browser is in full screen. Here are some example:
https://imgur.com/a/Ug6eQlp and https://imgur.com/a/bPrVg5y
This is my javascript function:
function init(){
imgObj = document.getElementById('minion');
immagine = document.getElementById('immagine_minion');
imgObj.style.position= 'absolute';
imgObj.style.top = '240px';
imgObj.style.left = '-300px';
imgObj.style.visibility='hidden';
appaer();
}
And this, for example, the method which moves it as soon as I open the page:
function appaer(){
immagine.src="../img/minion_dx.png";
if (parseInt(imgObj.style.left)<200) {
imgObj.style.left = parseInt(imgObj.style.left) + 5 + 'px';
imgObj.style.visibility='visible';
animate = setTimeout(appaer,20);
} else
stop();
}
How can I make it fit for every screen resolution?
this should get you started
var stage_number = 0
function go_to_next_stage() {
stage_number++
var stage = document.getElementById("stage" + stage_number)
me.style.left = getComputedStyle(stage).getPropertyValue("left")
me.style.top = getComputedStyle(stage).getPropertyValue("top")
if (stage_number > 3) stage_number = 0
}
img {
position: absolute;
left: -100px;
top: 0;
transition: left 2s, top 2s
}
.stage {
width: 100px;
height: 100px;
border: 1px solid black;
position: absolute;
}
#stage1 {
left: 0;
top: 0;
}
#stage2 {
right: 0;
top: 0;
}
#stage3 {
right: 0;
bottom: 0;
}
#stage4 {
left: 0;
bottom: 0;
}
div {
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
<img id="me" src="https://de.gravatar.com/userimage/95932142/195b7f5651ad2d4662c3c0e0dccd003b.png?size=100" />
<div onclick="go_to_next_stage()">click anywhere to continue</div>
<div class="stage" id="stage1">
</div>
<div class="stage" id="stage2">
</div>
<div class="stage" id="stage3">
</div>
<div class="stage" id="stage4">
</div>

Insert new Div below the div clicked

How to insert a new node(create with javascript) under the clicked node?.
At the moment it crosses the original div, I do not want that it crosses, it should remain in its origin
let parent = document.getElementById("parent");
parent.addEventListener("click", function(event) {
var currentSelection, currentRange, currentNode, newDiv, newContent;
currentSelection = window.getSelection();
currentRange = currentSelection.getRangeAt(0);
currentNode = currentRange.startContainer;
console.log(currentNode.nodeValue);
newDiv = document.createElement("div");
newDiv.className = 'nuevo';
newContent = document.createTextNode("holanda");
newDiv.appendChild(newContent);
this.appendChild(newDiv)
});
.nuevo {
width: auto;
height: auto;
background: red;
display: inline-block;
margin-top: 1em;
z-index: 3;
}
#parent>div {
float: left;
z-index: 1;
}
<div id="parent" contenteditable=true style="border: black 2px solid; height:200px">
<div>hello</div>
<div> *** </div>
<div>world</div>
</div>
result:
when clicked the word world
when clicked the word ***
Utilizing the offsetLeft property to locate new append elements:
let parent = document.getElementById("parent");
let rootElements = document.querySelectorAll("div.root");
for (let i = 0; i < rootElements.length; i++ ) {
rootElements[i].addEventListener("click", function(event) {
var currentSelection, currentRange, currentNode, newDiv, newContent;
currentSelection = window.getSelection();
currentRange = currentSelection.getRangeAt(0);
currentNode = currentRange.startContainer;
// console.log(currentNode.nodeValue);
newDiv = document.createElement("div");
newDiv.className = 'nuevo';
newContent = document.createTextNode("holanda");
newDiv.appendChild(newContent);
let xPos = event.currentTarget.offsetLeft;
let newEle = parent.appendChild(newDiv);
newEle.style.left = xPos + "px";
});
}
#parent {
position: relative;
left: 0px;
}
.nuevo {
display: block;
width: fit-content;
height: auto;
background: red;
position: relative;
}
.root {
vertical-align: top;
display: inline-block;
}
<div id="parent" contenteditable=true style="border: black 2px solid; height:200px">
<div class = "root">hello</div>
<div class = "root">***</div>
<div class = "root">world</div>
</div>
Update: one more way to achieve the goal
Append every new stack which actually has the same number of elements as first line. Utilize display: flex property on every new stack, and then give the inner elements corresponding width as same as their ancestor by flex-basis (why not width? this is another problem because of characteristic of flex property).
And let content of that only element which we want for visibly appending to extend the space for itself.
let parent = document.getElementById("parent");
let rootElements = document.querySelectorAll("div.root");
for (let i = 0; i < rootElements.length; i++ ) {
rootElements[i].addEventListener("click", function(event) {
newStack = document.createElement("div");
newStack.className = 'stack';
for (let j = 0; j < rootElements.length; j++) {
let grid = document.createElement("div");
grid.className = 'flexItem';
grid.setAttribute("style", "flex-basis:" + rootElements[j].getBoundingClientRect().width + "px");
if (i===j) {
grid.className += ' nuevo';
grid.textContent = 'holanda';
}
newStack.appendChild(grid)
}
parent.appendChild(newStack);
});
}
#parent {
font-size: 0px; // For eliminating gap between inline-blocks
}
.stack {
display: flex;
}
.flexItem {
flex: 0 1;
}
.nuevo {
height: auto;
background: red;
position: relative;
font-size: 16px;
}
.root {
display: inline-block;
font-size: 16px;
}
<div id="parent" contenteditable=true style="border: black 2px solid; height:200px">
<div class = "root">hello</div>
<div class = "root">*******</div>
<div class = "root">world</div>
</div>
Attach the event listener to each one of the divs inside parent so that you can use them to append your elements, also, change the display property of nuevo to block
let items = document.querySelectorAll("#parent > div");
for (var i = 0; i < items.length; i++) {
var item = items[i];
item.addEventListener("click", function(event) {
var newDiv = document.createElement("div");
newDiv.className = 'nuevo';
newDiv.appendChild(document.createTextNode("holanda"));
newDiv.style.left = this.offsetLeft + 'px';
this.parentNode.appendChild(newDiv);
});
}
.nuevo {
width: auto;
height: auto;
background: red;
display: block;
clear: both;
position: relative;
}
#parent>div {
float: left;
}
#parent {
position: relative;
left: 0px;
}
<div id="parent" contenteditable=true style="border: black 2px solid; height:200px">
<div>hello</div>
<div> *** </div>
<div>world</div>
</div>

Strange "nth-of-type" behavior

Here is just another approach for table-style layout using <ul> and <li>.
Each <ul> is a row, and each <li> is a cell.
The 1st <ul> is a header row, so it has a special styling which works fine.
For the widths of each columns, I would like to add "individual styling", using the advantage of "nth-of-child" instead of class.
Here is the HTML&CSS content:
var D, T, R;
function I() {
D = document.getElementById("D");
R = document.getElementById("R");
// To keep 1st row always visible.
D.onscroll = function() {
R.style.top = D.scrollTop + "px";
}
// This is just arbitrary content
var k = ["Va", "Vb"];
for (var i = 0; i < 500; i++) {
var e = document.createElement("ul");
D.appendChild(e);
for (var j = 0; j < 3; j++) {
var d = document.createElement("li");
e.appendChild(d);
d.innerHTML = (!j) ? i : k[j - 1];
}
}
}
I();
#D {
position: absolute;
left: 250px;
right: 50px;
top: 50px;
bottom: 50px;
background-color: #ff8;
overflow: auto;
white-space: nowrap;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
ul li {
display: table-cell;
}
ul:nth-child(odd) {
background: #eee;
}
ul:nth-child(even) {
background: #ddd;
}
ul:first-of-type {
background: #888;
color: #00f;
position: relative;
}
#D ul li:nth-of-type(1) {
width: 100px;
}
#D ul li:nth-of-type(2) {
width: 200px;
}
#D ul li:nth-of-type(3) {
width: 300px;
}
<div id="D">
<ul id="R">
<!-- 假行 Fake row -->
<li>请不要说谎:</li>
<li>这个不是表格 (table)!!!<br>
<div style="position:relative; left:0; right:0;"><select style="width:100%;">
<option>全部</option>
</select></div>
</li>
<li>这是2D目录(ul和li)!!!</li>
</ul>
</div>
NOTE: This is a test content and not production part, so please don't comment on the <style> to be in the <div> element or why I am not just using <table>.
NOTE: The use of "nth-of-type(1)" and not "first-of-type" here is just for convenience.
THE RESULT: columns 2 and 3 works perfect. Column one remains "auto" - not 100px wide
What I am doing wrong?

Implement nav dots to my slider?

I've been messing around with my slider and I got it to slide by itself. The problem is, there is no way you can manually view the slides. I would like to add navigation dots on the bottom so you can skim through the slides without having to view them as the slider goes along. If you could help me with this it would be greatly appreciated.
My slider html:
<div id="slider-container">
<div style="position: relative">
<div class="slide"><img id="slide_1" src="images/slide_1.jpg"/></div>
<div class="slide"><img id="slide_2" src="images/slide_2.jpg"/></div>
<div class="slide"><img id="slide_3" src="images/slide_3.jpg"/></div>
<div class="slide"><img id="slide_4" src="images/slide_4.jpg"/></div>
<div class="slide"><img id="slide_5" src="images/slide_5.jpg"/></div>
<div class="slide"><img id="slide_6" src="images/slide_6.jpg"/></div>
</div>
</div>
My slider css:
.slide-container {
display:block;
}
.slide {
top:0;
width:760px;
height:420px;
display:block;
position:absolute;
transform:scale(0);
transition:all .7s;
}
.slide img {
width:100%;
height:100%;
border-radius:6px;
border:1px solid #95ca1a;
}
My slider javascript:
$(document).ready(function() {
(function (){
var count = $(".slide > img").length;
var current = 1;
var sliderNext = 2;
$("img[id^='slide_']").fadeOut(0);
$("#slide_" + current).fadeIn(300);
var loop = setInterval(function() {
$("#slide_" + current).fadeOut(300);
$("#slide_" + sliderNext).fadeIn(300);
(sliderNext >= count) ? sliderNext = 1 : sliderNext++;
(current >= count) ? current = 1 : current++;
}, 3000)
})()
});
Here's an example of what I mean by nav dots:
CSS Slider - Codepen
First create list of dots, you can do it manually by creating list of "li" tags or can create it via jQuery.
here is code
<ol>
<li></li>
<li></li>
<li></li>
</ol>
number of "li" element should match with number of images
then have following css
#slider-container {
position:relative;
overflow:hidden;
width:100%;
height:380px;
display:inline-block;
}
.slide {
top:0;
width:100%;
display:inline-block;
}
.slide img {
width:100%;
height:100%;
border-radius:6px;
border:1px solid #95ca1a;
}
/******* css of dots ****/
ol{
list-style= none;
width:100%;
}
ol li{
background: #888;
border-radius: 50%;
display: inline-block;
width:20px;
height:20px;
cursor: pointer;
}
then add following jQuery stuff
$('ol li').bind('click', function(){
var index = $(this).index() + 1;
$(".active").fadeOut(300);
$("#slide_" + index).fadeIn(300);
$(".slide").removeClass("active");
$("#slide_" + index).addClass("active");
});
this code will hide active image and shows selected image
here is Fiddle example
hope it will help you
Here is a carousel script I wrote for a project. This allows you to click forward and backward and also on the dots. It's also dynamic so if you have 1 image, there are no dots or scroll bars, if you have 2 images there are the bars to go right and left but no dots, once you have three or more images the dots will be applied.
JsFiddle
HTML
<div class="carousel-container">
<div class="left-arrow"></div>
<div class="right-arrow"></div>
<div class="carousel-image-holder">
<img src="http://digitaljournal.com/img/8/7/8/4/4/i/1/1/7/o/ulingan_kids.jpg" />
<img src="http://freethoughtblogs.com/taslima/files/2012/06/22-funny2.jpg" />
<img src="http://blog.metrotrends.org/wp-content/uploads/2013/09/childPoverty.jpg" />
<img src="http://www.chinadaily.com.cn/china/images/2010WenUN/attachement/jpg/site1/20100921/0013729ece6b0e01d9691a.jpg" />
</div>
</div>
<div class="clear"></div>
<div class="carousel-buttons-container">
<ul></ul>
</div>
CSS
.clear{clear:both;}
.carousel-container{
width: 600px;
height: 360px;
float: left;
margin: 0;
padding: 0;
position: relative;
overflow: hidden;
}
.right-arrow{
width: 60px;
height: 100%;
background-color: rgba(0,0,0,.5);
position: absolute;
right: 0;
margin: 0;
padding: 0;
z-index: 2;
}
.left-arrow{
width: 60px;
height: 100%;
background-color: rgba(0,0,0,.5);
position: absolute;
left: 0;
margin: 0;
padding: 0;
z-index: 2;
}
.carousel-image-holder{
height:360px;
width: 2400px;
margin: 0;
padding: 0;
position: absolute;
z-index: 1;
}
.carousel-image-holder img{
width: 600px;
float: left;
margin: 0;
padding: 0;
display: inline-block;
}
.carousel-buttons-container{
width: 600px;
text-align: center;
margin: 15px 0 0 0;
padding: 0;
}
.carousel-buttons-container ul{
list-style-type: none;
margin: 0;
padding: 0;
}
.carousel-buttons{
background-color: #dddddd;
height: 18px;
width: 18px;
border-radius: 50%;
display: inline-block;
margin: 0 10px 0 0;
padding: 0;
cursor: pointer;
}
.carousel-buttons:last-of-type{
margin: 0;
}
.active{
background-color: #e67e22;
}
JQUERY
$(".left-arrow").hide();
var numImgs = $('div.carousel-image-holder img').length;
var addId = numImgs;
if(numImgs == 2){
var clicked = 0;
imgCount = numImgs-2;
}else if(numImgs <= 1){
$(".right-arrow").hide();
}else{
var clicked = 1;
imgCount = numImgs-1;
}
if(numImgs > 2){
for (var i=0; i<numImgs; i++){
$("ul").prepend('<li class="carousel-buttons" id="carousel'+addId+'"></li>');
var addId = addId - 1;
}
}else{
}
$(".carousel-buttons").click(function(){
var findIdClicked = $(this).attr("id");
var splitString = findIdClicked.split("carousel")
var findTheNumb = splitString[1];
$(".carousel-buttons").removeClass("active");
$(this).addClass("active");
clicked = parseInt(findTheNumb);
var adjustNumberforSlide = findTheNumb-1;
$(".carousel-image-holder").animate({"left": -(600*adjustNumberforSlide)+"px"});
console.log(clicked);
if(findTheNumb == 1){
$(".left-arrow").hide();
$(".right-arrow").show();
}else if (findTheNumb == numImgs){
$(".right-arrow").hide();
$(".left-arrow").show();
}else{
$(".right-arrow").show();
$(".left-arrow").show();
}
});
$(".carousel-buttons-container").find("li").first().addClass("active");
$(".right-arrow").click(function(){
if (clicked < imgCount){
$(".carousel-image-holder").animate({"left": "-=600px"});
console.log(clicked);
}else{
$(".carousel-image-holder").animate({"left": "-=600px"});
$(".right-arrow").hide();
console.log(clicked);
}
clicked = clicked+1;
$(".left-arrow").show();
$(".carousel-buttons").removeClass("active");
$("#carousel"+clicked).addClass("active");
});
$(".left-arrow").click(function(){
if (clicked > 2){
$(".carousel-image-holder").animate({"left": "+=600px"});
console.log(clicked);
}else{
$(".carousel-image-holder").animate({"left": "+=600px"});
$(".left-arrow").hide();
console.log(clicked);
}
$(".right-arrow").show();
clicked = clicked-1;
$(".carousel-buttons").removeClass("active");
$("#carousel"+clicked).addClass("active");
});
I'll clean up the spacing, just wanted to get this posted

Categories

Resources