Animate line wrapping of inline-block elements on content change - javascript

I have a container with a fixed width and overflow: auto; set.
It contains multiple items (display: inline-block;), also with fixed dimensions.
So if the container has enough children, the items will wrap around and create a grid-like pattern.
Now I dynamically remove children from the beginning and want to animate the position change of the items that are filling up the freed space and moving up from the start of a line to the end of the line above.
var counter = 1;
document.getElementById("additem").onclick = function() {
var item = document.createElement("div");
item.innerText = counter;
counter++;
document.getElementById('container').appendChild(item);
}
document.getElementById("removeitem").onclick = function() {
document.getElementById('container').removeChild(
document.getElementById('container').children[0]
);
}
#container {
width: 280px;
overflow: auto;
border: 1px solid red;
padding: 5px;
text-align: center;
}
#container > div {
width: 80px;
height: 90px;
border: 1px solid green;
margin: 5px;
display: inline-block;
}
<button id="additem">add item</button>
<button id="removeitem">remove item</button>
<div id="container">
</div>
EDIT: I am also able to use jQuery to accomplish this behaivor.

A reasonably clean solution is to use an inline style that sets the removed element's opacity to 0, accompanied by a transition and a setTimeout timed to run as soon as the transition finishes, effectively fading out the element and then sliding everything else into place. Here's a quick snippet I put together:
var counter = 1;
document.getElementById("additem").onclick = function() {
var item = document.createElement("div");
item.innerText = counter;
counter++;
document.getElementById('container').appendChild(item);
}
document.getElementById("removeitem").onclick = function() {
document.getElementById('container').children[0].setAttribute('style', 'opacity: 0');
window.setTimeout(function() {
document.getElementById('container').removeChild(
document.getElementById('container').children[0]
)
}, 300);
}
#container {
width: 280px;
overflow: auto;
border: 1px solid red;
padding: 5px;
text-align: center;
}
#container>div {
width: 80px;
height: 90px;
border: 1px solid green;
margin: 5px;
display: inline-block;
transition: opacity 0.3s;
}
<button id="additem">add item</button>
<button id="removeitem">remove item</button>
<div id="container">
</div>

Related

Create iframes showing the end of each one as if I had dragged the scrollbar to the end

In short: what I only need is this graphic map and the team symbol, without the other data appearing on the screen, wasting space and without the scrollbar on the right side that covers the end of the graphic.
var myIframe = document.getElementById('iframe');
myIframe.onload = function(){
myIframe.contentWindow.scrollTo(0,500);
};
<iframe id="iframe" src="https://www.sofascore.com/event/9626475/attack-momentum/embed"></iframe>
When creating the iframe, it comes with some unwanted data that only takes up space, as I left circled in the image below:
When I decrease the size of the iframe to take up less space, this happens:
What I would like to happen is that when creating the iframe, it would already scroll to the end, thus automatically:
Is there anything I can put in my HTML or script that can do this automatic scrolling when creating iframes?
I also tried using .style("margin-top","-90px"); but doing so happens that the values exceed the iframe limits getting on top of the previous ones:
If you want to do the complete test, use this code and create a CSV file with the sofascore ids (SofaScore_Live.csv):
<html>
<head>
<style>
{
box-sizing: border-box;
}
.vl {
border-left: 3px solid red;
height: 1000px;
position: absolute;
left: 30.3%;
margin-left: -3px;
top: 0;
}
.vl2 {
border-left: 3px solid red;
height: 1000px;
position: absolute;
left: 10.9%;
margin-left: -3px;
top: 0;
}
.vl3 {
border-left: 3px solid red;
height: 1000px;
position: absolute;
left: 69%;
margin-left: -3px;
top: 0;
}
.matches {
text-align:center;
float: left;
width: 700px;
border: 1px solid white;
border-collapse: collapse;
}
.column {
text-align:center;
float: left;
width: 700px;
border: 1px solid white;
border-collapse: collapse;
}
.grid {
float: left;
width: 100%;
}
.row:after {
content: "";
display: table;
clear: both;
}
.button {
background-color: #33ccff;
color: black;
font-weight: bold;
}
input[type=submit] {
background-color: #33ccff;
color: black;
font-weight: bold;
}
html {
overflow: scroll;
overflow-x: hidden;
}
::-webkit-scrollbar {
width: 0px; /* remove scrollbar space /
background: transparent; / optional: just make scrollbar invisible /
}
/ optional: show position indicator in red */
::-webkit-scrollbar-thumb {
background: #FF0000;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.1.1/d3.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-fetch#3"></script>
</script>
</head>
<body style="background-color:black;">
<div class="vl"></div>
<div class="vl2"></div>
<div class="vl3"></div>
<div style="color:white;font-weight:bold" class="grid games" id="jogos-sofascore">
</div>
<script id="script-da-caixa-de-selecao-suspensa-5">
var select_5 = d3.select("#jogos-sofascore")
.append("div")
.attr("id","select-box-5")
.style("width","100%")
function valorparaiframe(iframevalue) {
let link = iframevalue;
return "https://www.sofascore.com/event/" + iframevalue + "/attack-momentum/embed";
}
async function update() {
let data = await d3.csv("./SofaScore_Live.csv");
let update_5 = select_5.selectAll(".matches")
.data(data,d=>d.id);
update_5.exit().remove();
// Enter new divs:
const enter = update_5.enter()
.append("div")
.attr("class","matches");
// Append the children to entered divs:
enter.append("iframe")
.attr("src",d => valorparaiframe(d.id))
.style("width","100%")
.style("height","110");
}
update();
setInterval(update,60000);
</script>
</div>
</body>
</html>
SofaScore_Live.csv CSV example:
id
9576375
9602988
9643997
9944904
9591418
9595065
9595129
9595043
9671970
9698797
9671975
9671974
9578901
iframes loaded from a different origin are protected by the same-origin-policy, which prevents you from accessing/modifying the content of it (which is why you can't use scrollTo etc,.).
As a workaround, if you know the height of the content in the iframe (which you can retrieve by going to the iframe source and getting the body's offsetHeight), you can set the height of the iframe to the height of the content. Then, you can wrap the iframe in a container, set the container's height, and scroll to the bottom of the container.
const container = document.querySelector('.iframe-container')
container.scrollTop = container.scrollHeight;
iframe {
height: 200px;
width: 100%;
border: none;
}
.iframe-container{
height:120px;
overflow:auto;
}
<div class="iframe-container">
<iframe id="iframe" src="https://www.sofascore.com/event/9626475/attack-momentum/embed"></iframe>
</div>
You can use the scroll(x, y) function:
scroll(0, 10000)

JavaScript change the border from middle to left and right,use transition prototype?

I don’t want use or i don't know how to use 'the CSS:after prototype' by javascript .
Now, I change it is by add height not width,and when i remove the class prototype, reback is a short time,no transtion.
What can i do for it?
this is my codepen link
<div class="block">
<div id="top">my block/div>
<div>
<button id="btn">submit</button>
</div>
</div>
.block {
height: 200px;
width: 250px;
margin:150px auto;
text-align: center;
}
#top {
margin-bottom: 20px;
height: 30px;
display: inline-block;
border-bottom: 3px solid;
transition: 1s all cubic-bezier(.46, 1, .23, 1.52);
}
.addtop {
border-bottom: 3px solid blue;
color: blue;
}
let btn = document.getElementById('btn');
btn.addEventListener('click',() => {
let topBlock = document.getElementById('top');
if(topBlock.classList.length > 0) {
topBlock.classList = [];
} else {
topBlock.classList.add('addtop');
}
});
Try this:
document.getElementById('top');
if(topBlock.classList.length > 0) {
topBlock.classList.remove('addtop');
} else {
topBlock.classList.add('addtop');
}
});
Also add to .top class:
border-bottom: 0px solid blue;

Create new div with different %width

I've created a section with one div.
The button 'click' adds new div each time when I click.
What I need: div 1 -> 100% width (section)
when I click:
div 1 and div2 (div 2 new) -> get 50% width each.
click again:
div1, div2 and div3 -> 30% width each.
click again:
div 4 goes to next line with the same width
Do you have any idea?
https://jsfiddle.net/Vova_Champion/tcyw64wq/6/
document.getElementById("button").onclick = function() {
let ok = true;
if (ok === true) {
let div = document.createElement('div');
div.className = 'new-div';
document.getElementsByTagName('section')[0].appendChild(div);
}
};
section {
display: flex;
height: 100px;
width: 200px;
background: red;
flex-wrap: wrap;
overflow: auto;
}
div {
display: block;
height: 30px;
width: 100%;
max-width: 30%;
background: blue;
margin: 5px 2px;
}
#button {
color: red
}
<button id="button">Click button</button>
<section id="section">
<div></div>
</section>
Use this div style:
div {
flex-grow: 1;
display:block;
height: 30px;
min-width: 30%;
background: blue;
margin: 5px 2px;
}
"Flex-grow" gives them "weight" inside the div, items with the same flex grow share the same portion of the available space. Min-width triggers the 4th div to go down since adding that to the same line would make their width 25%.
If you need any further explanation, please ask!
I would also suggest some flex-grow and a conditional class to fix width after 3 items. Here is my try ;)
I have also used css calc.
(function() {
const section = document.getElementById('section');
function addDiv() {
const div = document.createElement('div');
div.className = 'new-div';
section.appendChild(div);
if (section.childNodes.length > 3) {
section.classList.add("fixedWith");
}
}
document.getElementById("button").onclick = function() {
addDiv();
};
document.addEventListener("DOMContentLoaded", function() {
addDiv();
});
})();
section {
display: flex;
height: 100px;
width: 200px;
background: red;
flex-wrap: wrap;
overflow: auto;
}
div {
flex-grow: 1;
min-width: calc(100% / 3 - 4px);
height: 30px;
background: blue;
margin: 5px 2px;
}
section.fixedWith div {
max-width: calc(100% / 3 - 4px);
}
#button {
color: red;
}
<html>
<body>
<button id="button">Click button</button>
<section id="section"></section>
</body>
<html>
Putting flex: 1 on the div says that it will take 1 fraction of the space in its parent. When another div is added, it then takes 1 of the two available fractions of space and so on. The flex-basis: 30%; effectively says that each flex item can take at most 30% of the available space for that row. Hopefully this fixes your problem!
section {
display: flex;
height: 100px;
width: 200px;
background: red;
flex-wrap: wrap;
overflow: auto;
}
div {
display: block;
height: 10px;
flex: 1;
flex-basis: 30%;
background: blue;
margin: 5px 2px;
}
#button {
color: red;
}

JavaScript and CSS not working as intended

In the following code, when I put the div with class thumb-bar, the JavaScript I have written works but if place use it after full-img div tag, it doesn't work also the CSS attribute cursor: pointer for the thumb-bar div is not applied.
Edit - I mean the click listeners I apply using JavaScript are not working
CSS:
body {
width: 640px;
margin: 0 auto;
}
.full-img {
position: relative;
display: block;
width: 640px;
height: 480px;
}
button {
border: 0;
background: rgba(150, 150, 150, 0.6);
text-shadow: 1px 1px 1px white;
border: 1px solid #999;
position: absolute;
cursor: pointer;
top: 2px;
left: 2px;
}
.thumb-bar img {
display: block;
width: 20%;
float: left;
cursor: pointer;
}
HTML:
<div class="thumb-bar"></div>
<div class="full-img">
<img class="displayed-img" src="images/pic1.jpg">
<button class="dark">Darken</button>
</div>
JavaScript:
var displayedImage = document.querySelector('.displayed-img');
var thumbBar = document.querySelector('.thumb-bar');
btn = document.querySelector('button');
var overlay = document.querySelector('.overlay');
for (var i = 1; i <= 5; i++) {
var newImage = document.createElement('img');
newImage.setAttribute('src', 'images/pic' + i + '.jpg');
thumbBar.appendChild(newImage);
newImage.addEventListener('click', function(e) {
displayedImage.setAttribute('src', e.target.getAttribute('src'))
});
}
Because you're floating .thumb-bar img, those images are taken out of the page flow which results in the .thumb-bar element to have a height of 0, which in turn causes subsequent content to not be pushed down. That means that the .full-img element is rendered on top of the images and obscures them from the mouse pointer.
You need to clear the floats in order to get the .full-img element to render below them. This can be done by either making sure the .thumb-bar clear it's own content:
.thumb-bar {
overflow: hidden;
}
... or make the .full-img element itself clear them:
.full-img {
clear: both;
}

How to properly animate a bar gliding?

I have two buttons, when a user clicks on them it gets underlined. However, I'd like the .underline to be animated/glide horizontally to the button that is being clicked on.
Demo: https://jsfiddle.net/ds1wr736/11/
As of right now, the .underline just appears and disapears when a button is clicked. How can I animate this to smoothly glide (x values changing) to the selected button without hacks and JQuery?
function switchTab(tab) {
if (tab === 1) {
document.getElementById("tab2").classList.add("underline");
document.getElementById("tab1").classList.remove("underline");
}
else if (tab === 2) {
document.getElementById("tab1").classList.add("underline");
document.getElementById("tab2").classList.remove("underline");
}
}
.bar {
background-color: gray;
padding: 20px;
}
.underline {
border-bottom: 5px solid red;
}
button {
width: 100px;
height: 50px;
background-color: white;
}
button:focus {
outline: none;
}
<div class="bar">
<button id='tab1' class="underline" onclick='switchTab(2)'>Tab 1</button>
<button id='tab2' onclick='switchTab(1)'>Tab 2</button>
</div>
Rather than animating a border I've created an additional element that reacts to the the click events. This allows us to track the position of the "underline" and scale and animate it between buttons when clicked.
This can be modified to accept hover events instead using mouseover instead of click.
let buttons = document.querySelectorAll('button');
buttons.forEach(button => {
button.addEventListener('mouseover', hoverboard); // Hover event
//button.addEventListener('click', hoverboard);
});
function hoverboard(e) {
const board = document.querySelector('.hoverboard');
// - 1 due to the border of the button
let width = this.offsetWidth - 1;
const firstChild = document.querySelector('.bar button:first-child');
const lastChild = document.querySelector('.bar button:last-child');
// - 19 due to padding being 20px on the left and removing 1 for the button's border
let left = this.offsetLeft - 19;
board.style.cssText = 'transform: translateX(' + left + 'px); width: ' + width + 'px;';
}
.bar {
position: relative;
background-color: gray;
padding: 20px;
}
.underline {
border-bottom: 5px solid red;
}
button {
width: 100px;
height: 50px;
background-color: white;
}
button:focus {
outline: none;
}
.hoverboard {
position: absolute;
width: 100px;
height: 3px;
background: red;
transition: transform .25s ease, width .25s ease;
}
<div class="bar">
<button id='tab1'>Tab 1</button>
<button id='tab2' style="width: 65px;">Tab 2</button>
<button>Tab 3</button>
<div class="hoverboard"></div>
</div>
Here ya go. Only the edited classes are here:
.underline:after {
border-bottom: 5px solid red;
animation-name: slideIn;
animation-duration: 1s;
width: 100%;
content: '';
position: absolute;
bottom: 0;
left: 0;
}
#keyframes slideIn {
from {width: 0;}
to {width: 100%;}
}
button{
position: relative;
width: 100px;
height: 50px;
background-color: white;
}
What I did is that I used the abstract after element on the buttons and positioned it absolute to it's relative button. And used css animation.

Categories

Resources