Equal height of children of unrelated parents - javascript

I want to have an equal height of two unrelated divs. Basically, I need to equalize the height of Parent B's child to Parent A's child. Below is the image to highlight what it is about:
Any idea how this can be accomplished with jQuery. Most of the equal height solutions I came across are about children of the same parent.
The code I used is for children within a container.
$(document).ready(function(){
$('.containers').each(function(){
var min_highestBox = 0;
$('.columns', this).each(function(){
if($(this).height() > min_highestBox) {
min_highestBox = $(this).height();
}
});
$('.columns',this).height(min_highestBox);
});
});
.containers {border:1px solid; width:100%; display:inline-block;}
.columns {border:1px solid red; padding: 20px; min-width:20%; float:left;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="containers">
<div class="columns">This is<br />the highest<br />column</div>
<div class="columns">One line</div>
<div class="columns">Four<br />lines<br />the highest<br />column</div>
</div>
<div class="containers">
<div class="columns">One line</div>
<div class="columns">Two<br>lines</div>
<div class="columns">One line</div>
</div>
I have tried it with a CSS grid but in this specific situation, a CSS grid is not a solution.
Update: the actual containers are both separate and independent of each other:
.a, .b {border:2px solid; padding: 25px; float:left; width: 200px;}
.a div, .b div {border:2px solid red;}
<div class="a">Parent A
<div>Child of A <br> some additional text</div>
</div>
<div class="b">Parent B
<div>Child of B</div>
</div>

In the case that they can't be placed inside a wrapper you can make use of a sorting from lowest to heighest and apply the heighest value to all affected nodes and a MutationObserver to easily monitor changes on these nodes to call the height-adjust routine again.
For equal height of parents:
$(document).ready(() => {
const selector = ".containers";
function resize() {
const nodes = $(selector)
.css("height", "auto")
.sort((a, b) => $(a).height() - $(b).height()),
heighest = nodes.last().height();
if (nodes.first().height() != heighest)
$(selector).css(`height`, `${heighest}px`);
}
resize();
const observer = new MutationObserver(resize);
$(selector).each((idx, el) => observer.observe(el, { childList: true, subtree: true }));
// Examples:
setTimeout(() => {
$(".columns").first().append("<br>Lorem<br>Ipsum<br>Dolor<br>sit<br>Amet");
}, 1500);
setTimeout(() => {
$(".columns").last().append("<br>Lorem<br>Ipsum<br>Dolor<br>sit<br>Amet");
}, 3000);
setTimeout(() => {
$(".columns").last().append("<br>Lorem<br>Ipsum<br>Dolor<br>sit<br>Amet");
}, 5000);
})
.containers {
border: 1px solid;
width: 100%;
display: inline-block;
}
.columns {
border: 1px solid red;
padding: 20px;
min-width: 20%;
float: left;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="containers">
<div class="columns">This is<br>the highest<br>column</div>
<div class="columns">One line</div>
<div class="columns">Four<br>lines<br>the highest<br>column</div>
</div>
<div class="containers">
<div class="columns">One line</div>
<div class="columns">Two<br>lines</div>
<div class="columns">One line</div>
</div>
For equal height of childs:
$(document).ready(() => {
const selector = ".columns";
function resize() {
const nodes = $(selector)
.css("height", "auto")
.sort((a, b) => $(a).height() - $(b).height()),
heighest = nodes.last().height();
if (nodes.first().height() != heighest)
$(selector).css(`height`, `${heighest}px`);
}
resize();
const observer = new MutationObserver(resize);
$(selector).each((idx, el) => observer.observe(el, { childList: true, subtree: true }));
// Examples:
setTimeout(() => {
$(".columns").first().append("<br>Lorem<br>Ipsum<br>Dolor<br>sit<br>Amet");
}, 1500);
setTimeout(() => {
$(".columns").last().append("<br>Lorem<br>Ipsum<br>Dolor<br>sit<br>Amet");
}, 3000);
setTimeout(() => {
$(".columns").last().append("<br>Lorem<br>Ipsum<br>Dolor<br>sit<br>Amet");
}, 5000);
})
.containers {
border: 1px solid;
width: 100%;
display: inline-block;
}
.columns {
border: 1px solid red;
padding: 20px;
min-width: 20%;
float: left;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="containers">
<div class="columns">This is<br>the highest<br>column</div>
<div class="columns">One line</div>
<div class="columns">Four<br>lines<br>the highest<br>column</div>
</div>
<div class="containers">
<div class="columns">One line</div>
<div class="columns">Two<br>lines</div>
<div class="columns">One line</div>
</div>

If you consider an extra wrapper you can do it with only CSS
.wrapper {
display: grid;
gap: 5px;
grid-auto-rows: 1fr; /* eqaul containers */
}
.containers {
border: 1px solid;
display: flex; /* equal childs */
}
.columns {
border: 1px solid red;
padding: 20px;
min-width: 20%;
}
<div class="wrapper">
<div class="containers">
<div class="columns">This is<br />the highest<br />column</div>
<div class="columns">One line</div>
<div class="columns">Four<br />lines<br />the highest<br />column</div>
</div>
<div class="containers">
<div class="columns">One line</div>
<div class="columns">Two<br>lines</div>
<div class="columns">One line</div>
</div>
</div>

Related

How to drag and drop a draggable element and swap its place with another element

I created six div elements, each with an id. Inside these six div elements, I created six img elements, each with an id.
Now I want to drag any image and drop it over any of the six div elements.
When I drag image 1 and drop it over div 5, then the div 5 image should move to div 1. How can I achieve this? Here is my code:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<interface id="interface">
<div id="div1"><img src="images/images/Number1.png" alt="one" id="drag1" draggable="true"></div>
<div id="div2"><img src="images/images/Number2.png" alt="two" id="drag2" draggable="true"></div>
<div id="div3"><img src="images/images/Number3.png" alt="three" id="drag3" draggable="true"></div>
<div id="div4"><img src="images/images/Number4.png" alt="four" id="drag4" draggable="true"></div>
<div id="div5"><img src="images/images/Number5.png" alt="five" id="drag5" draggable="true"></div>
<div id="div6"><img src="images/images/Number6.png" alt="six" id="drag6" draggable="true"></div>
</interface>
<script src="app.js"></script>
</body>
</html>
Javascript code starts here:
console.log("Get Started");
const imgboxes = document.querySelectorAll("img");
console.log(imgboxes);
const divBoxes = document.querySelectorAll("div");
console.log(divBoxes);
for (imgbox of imgboxes) {
imgbox.addEventListener('dragstart', (e) => {
console.log("dragStart triggred");
setTimeout(() => {
e.target.className = "hide";
}, 0);
})
}
for (imgbox of imgboxes) {
imgbox.addEventListener('dragend', (e) => {
console.log("dragEnd triggred");
e.target.className = "imgbox"
})
}
for (divbox of divBoxes) {
divbox.addEventListener('dragover', (e) => {
console.log("dragOver triggred");
e.preventDefault();
})
divbox.addEventListener('dragenter', () => {
console.log("dragEnter triggred");
})
divbox.addEventListener('dragleave', () => {
console.log("dragLeave triggred");
})
divbox.addEventListener('drop', (e) => {
console.log("dragDrop triggred");
e.target.appendChild(imgbox);
})
}
CSS code is here:
body{
padding: 0;
margin: 0 auto;
}
#div1, #div2, #div3, #div4, #div5, #div6{
float: left;
width:85px;
height:85px;
margin: 20px;
padding: 0px;
border: 1px solid black;
align-items: center;
justify-content: center;
text-align: center;
}
#drag1, #drag2, #drag3, #drag4, #drag5, #drag6{
height: 80px;
width: 80px;
margin-top: 2px;
}
#interface{
display: flex;
flex-direction: row;
margin: 100px auto;
align-items: center;
justify-content: center;
}
.hide{
display: none;
}
.imgbox{
height: 80px;
width: 80px;
margin-top: 2px;
}
Based on swapping child elements of div using JavaScript by drag and drop, here is a demo.
The event.target.id is stored within the dragStart() function.
This dragged image id can then be retrieved in the drop() function.
Then that id can be used to retrieve the draggedImage.
Within drop(), we can test to make sure that the image is not being dropped back into the same container.
appendChild() removes the child element being appended from its previous parent.
const images = document.querySelectorAll("img");
const containers = document.querySelectorAll(".container");
images.forEach((image) => {
image.addEventListener("dragstart", dragStart);
image.addEventListener("dragend", dragEnd);
});
containers.forEach((container) => {
container.addEventListener("dragover", dragOver);
container.addEventListener("drop", drop);
});
function dragStart(event) {
event.dataTransfer.setData("draggedImageId", event.target.id);
setTimeout(() => event.target.classList.toggle("hidden"));
}
function dragEnd(event) {
event.target.classList.toggle("hidden");
}
function dragOver(event) {
event.preventDefault();
}
function drop(event) {
const draggedImageId = event.dataTransfer.getData("draggedImageId");
const draggedImage = document.getElementById(draggedImageId);
const fromContainer = draggedImage.parentNode;
const toContainer = event.currentTarget;
if (toContainer !== fromContainer) {
fromContainer.appendChild(toContainer.firstElementChild);
toContainer.appendChild(draggedImage);
}
}
.row {
display: flex;
column-gap: 1rem;
padding: 1rem;
border: solid 2px black;
background: pink;
}
.container {
width: 100px;
height: 200px;
padding: 1rem;
border: solid 2px black;
background: white;
}
.hidden {
display: none;
}
<div class="row">
<div class="container">
<img id="drag1" src="https://source.unsplash.com/random/80x80/?cat" draggable="true" />
</div>
<div class="container">
<img id="drag2" src="https://source.unsplash.com/random/80x80/?fruit" draggable="true" />
</div>
<div class="container">
<img id="drag3" src="https://source.unsplash.com/random/80x80/?car" draggable="true" />
</div>
<div class="container">
<img id="drag4" src="https://source.unsplash.com/random/80x80/?dog" draggable="true" />
</div>
</div>

Elements traversing across parent, z-index

For any element that is clicked in the stack, the target element should be assigned a higher z-index than all of those that come before it in the DOM. Then it should translateY() pixels up to the first element.
The desired result is for the target element to sit on top of the first element in the parent. Yet there is a bug where it makes it appear that some elements get a lower z-index . If this could be refactored better as well how could it be improved?
const divs = document.querySelectorAll("div");
divs.forEach((div) => {
div.addEventListener("click", (event) => {
let i = 0;
let previous_sibling = event.target.previousElementSibling;
while (previous_sibling != null) {
i++;
previous_sibling = previous_sibling.previousElementSibling;
}
event.target.style.cssText = `
position: relative;
z-index: ${i + 1};
transform: translateY(-${i * 45}px);
`;
})
})
.box {
width: 300px;
height: 45px;
/* border: 1px solid; */
margin: auto;
}
section {
margin-top: 50px;
}
div {
transition: transform .75s linear;
}
#box1 {
background: red;
}
#box2 {
background: blue;
}
#box3 {
background: green;
}
#box4 {
background: orange;
}
#box5 {
background: purple;
}
#box6 {
background: teal;
}
<section>
<div class="box" id="box1">1</div>
<div class="box" id="box2">2</div>
<div class="box" id="box3">3</div>
<div class="box" id="box4">4</div>
<div class="box" id="box5">5</div>
<div class="box" id="box6">6</div>
<div class="box" id="box1">7</div>
<div class="box" id="box2">8</div>
<div class="box" id="box3">9</div>
<div class="box" id="box4">10</div>
<div class="box" id="box5">11</div>
<div class="box" id="box6">12</div>
</section>
Currently the z-index gets calculated by the elements DOM position due to the use of previousElementSibling and the simple counter. Since translateY does not change the position of the elements in the DOM they can never be out of order. For example numer #3 can never be on top of #4 because it never is in the DOM. To change this behaviour you could simply store the highest z-index (here in the dataset of the section) and reuse / add to it.
const divs = document.querySelectorAll("div");
divs.forEach((div) => {
div.addEventListener("click", (event) => {
//REM: Get the highest z-index
let tCurrentZ = ~~div.parentNode.dataset.zindex;
let i = 0;
let previous_sibling = event.target.previousElementSibling;
while (previous_sibling != null) {
i++;
previous_sibling = previous_sibling.previousElementSibling;
}
event.target.style.cssText = `
position: relative;
z-index: ${tCurrentZ};
transform: translateY(-${i * 45}px);
`;
//REM: Increase the highest z-index
div.parentNode.dataset.zindex = tCurrentZ + 1
})
})
.box {
width: 300px;
height: 45px;
/* border: 1px solid; */
margin: auto;
}
section {
margin-top: 50px;
}
div {
transition: transform .75s linear;
}
#box1 {
background: red;
}
#box2 {
background: blue;
}
#box3 {
background: green;
}
#box4 {
background: orange;
}
#box5 {
background: purple;
}
#box6 {
background: teal;
}
<section>
<div class="box" id="box1">1</div>
<div class="box" id="box2">2</div>
<div class="box" id="box3">3</div>
<div class="box" id="box4">4</div>
<div class="box" id="box5">5</div>
<div class="box" id="box6">6</div>
<div class="box" id="box1">7</div>
<div class="box" id="box2">8</div>
<div class="box" id="box3">9</div>
<div class="box" id="box4">10</div>
<div class="box" id="box5">11</div>
<div class="box" id="box6">12</div>
</section>

Jquery Start from Beginning When A Div Reaches The End of Scroll

So i was trying to create a automatic horizontal scroll div which keeps on scrolling its elements in an infinite loop. This is what I have achieved so far:
$(document).ready(function(){
function animatethis(targetElement, speed) {
var scrollWidth = $(targetElement).get(0).scrollWidth;
var clientWidth = $(window).width();
$(targetElement).animate({ scrollLeft: scrollWidth - clientWidth },
{
duration: speed,
complete: function () {
$(targetElement).scrollLeft(0);
animatethis(targetElement, speed);
}
});
};
animatethis($('.editors-pick-slideshow'), 10000);
});
.editors-pick-slideshow {
border: 1px solid;
width: 100%;
height: 500px;
overflow-y: hidden;
overflow-x: auto;
display: block;
margin: auto;
}
.editors-pick-container {
width: 3150px;
}
.editors-pick-container > div {
display: inline-block;
width: 1000px;
margin: 0px 20px;
}
.editors-pick-elements {
display: grid;
grid-template-columns: 1fr 1fr;
max-width: 1000px;
min-width: 300px;
border: 1px solid green;
height: 500px;
grid-gap: 20px;
margin: auto;
}
.pick1 {
background-color: #ccc;
}
.pick2 {
background-color: #ccc;
}
.pick3 {
background-color: #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="editors-pick-slideshow">
<div id="editorsPickContainer" class="editors-pick-container">
<div>
<div id="group1" class="editors-pick-elements">
<div class="pick1">Grid 1</div>
<div class="pick2">Grid 1</div>
</div>
</div>
<div>
<div id="group2" class="editors-pick-elements">
<div class="pick1">Grid 2</div>
<div class="pick2">Grid 2</div>
</div>
</div>
<div>
<div id="group3" class="editors-pick-elements">
<div class="pick1">Grid 3</div>
<div class="pick2">Grid 3</div>
</div>
</div>
</div>
</div>
As you can see in above snippet that when the animation reaches the end of the div it starts abruptly from the beginning. What I want to achieve here is when the animation reaches the end it should continue its flow towards the grid 1 element and keep on scrolling smoothly in an infinite manner. I hope what I am saying makes sense.
You can add a boolean parameter indicating which direction to scroll toward and negate the parameter each time the animation is complete.
function animatethis(targetElement, toEnd, speed) {
let pos;
if (toEnd) {
let scrollWidth = $(targetElement).get(0).scrollWidth;
let clientWidth = $(window).width();
pos = scrollWidth - clientWidth;
} else {
pos = 0;
}
$(targetElement).animate({
scrollLeft: pos
}, {
duration: speed,
complete: function() {
animatethis(targetElement, !toEnd, speed);
}
});
}
animatethis($('.editors-pick-slideshow'), true, 10000);
Live Example:
$(document).ready(function(){
function animatethis(targetElement, toEnd, speed){
let pos;
if(toEnd){
let scrollWidth = $(targetElement).get(0).scrollWidth;
let clientWidth = $(window).width();
pos = scrollWidth - clientWidth;
} else {
pos = 0;
}
$(targetElement).animate({ scrollLeft: pos},
{
duration: speed,
complete: function () {
animatethis(targetElement, !toEnd, speed);
}
});
}
animatethis($('.editors-pick-slideshow'), true, 10000);
});
.editors-pick-slideshow {
border: 1px solid;
width: 100%;
height: 500px;
overflow-y: hidden;
overflow-x: auto;
display: block;
margin: auto;
}
.editors-pick-container {
width: 3150px;
}
.editors-pick-container > div {
display: inline-block;
width: 1000px;
margin: 0px 20px;
}
.editors-pick-elements {
display: grid;
grid-template-columns: 1fr 1fr;
max-width: 1000px;
min-width: 300px;
border: 1px solid green;
height: 500px;
grid-gap: 20px;
margin: auto;
}
.pick1 {
background-color: #ccc;
}
.pick2 {
background-color: #ccc;
}
.pick3 {
background-color: #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="editors-pick-slideshow">
<div id="editorsPickContainer" class="editors-pick-container">
<div>
<div id="group1" class="editors-pick-elements">
<div class="pick1">Grid 1</div>
<div class="pick2">Grid 1</div>
</div>
</div>
<div>
<div id="group2" class="editors-pick-elements">
<div class="pick1">Grid 2</div>
<div class="pick2">Grid 2</div>
</div>
</div>
<div>
<div id="group3" class="editors-pick-elements">
<div class="pick1">Grid 3</div>
<div class="pick2">Grid 3</div>
</div>
</div>
</div>
</div>

scrollIntoView() moves the whole page layout up

The whole page layout moves up when we use scrollIntoView(true). For my requirement I need to use true parameter. I need to avoid this move. I posted a working copy of this code in https://jsfiddle.net/7v4t31p0/ Thank you in advance.
.body {
display: flex;
width: 100%;
border: 1px solid gray;
}
.left {
flex: 0 0 200px;
}
.right {
flex: 1 1 auto;
border: 1px solid green;
}
.details {
display: flex;
width: 100%;
}
.links {
display: flex;
flex-direction: column;
}
.content {
max-height: 100px;
overflow-y: auto;
flex: 1 1 auto;
}
.content div {
min-height: 100px;
}
<div>
<div>
Header
</div>
<div class="body">
<div class="left">
Left panel
</div>
<div class="right">
<div class="details">
<div class="links">
<button id='btn1'>link 1</button>
<button id='btn2'>link 2</button>
<button id='btn3'>link 3</button>
</div>
<div class="content">
<div id="content1"> Content 1</div>
<div id="content2"> Content 2</div>
<div id="content3"> Content 3</div>
</div>
</div>
</div>
</div>
</div>
Use this instead of using true, the default value of true is block: start and inline: nearest the body will go up(start). In your case its your parent element.
yourContent.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' })
Thank you all. I used ScrollTop instead of ScrollIntoView().
Here is my working code demo https://jsfiddle.net/6gu4rkc1/
content1.parentNode.scrollTop = content1.offsetTop - 30;

Rendering two div in a div horizantally

I have a parent div having two child divs which are in horizantal ,Now I want to add other div such that the pagination should come.
Here is the code.
<div id="parent">
<div id="left"></div>
<div id="right"></div>
</div>
Here, If i add other div to 'parent',It will append at last,but should not be shown and pagination should come.
Using floats, I am making the div's horizantal.I have to show only two div's,After that pagination should come.
This is just a DEMO:
HTML:
<div id="parent">
<div id="wrapper">
<div id="left">window 1</div>
<div id="right">window 2</div>
</div>
</div>
<div id="paginator"><span id="prev">Previous</span><span id="next">Next</span></div>
CSS:
#parent {
width: 850px;
overflow: hidden;
padding: 10px;
height: 320px;
border: 1px solid #f00
}
#wrapper div {
width: 400px;
border: 1px solid #ccc;
height: 300px;
display:inline-block;
margin: 10px
}
#paginator {
margin: 10px;
display: block
}
#paginator span {
width: 30px;
padding: 5px;
margin: 10px;
background: #1f1f1f;
color: #fff;
}
JQUERY:
$(function() {
$('#next').click(function() {
$('#wrapper').append($('<div>window 3</div><div>window 4</div>')); // you can add div using other way
$('#wrapper').animate({
marginLeft: '-=860px'
},
500, 'linear');
});
$('#prev').click(function() {
$('#wrapper').animate({
marginLeft: '+=860px'
},
500, 'linear');
});
});
Not sure I understand your question, but I'll give it a shot...
<div id="parent">
<div id="left"></div>
<div id="right"></div>
</div>
<div style="clear:both"></div>
<div id="pagination"></div>
... is this what you mean to do?

Categories