javascript applied border for group of absolute positioned images - javascript

I'm trying to apply a border to a div group of images (that need to be in absolute position mode, because the user select and move them around), and for some reason can't figure out why it doesn't work. In my code, I move the images around inside the div container, and want the overall div container to show a proper border, based on the size of the things inside. Here is some simplified code, perhaps only one small bug, I can't see it, to get it working.
Editing the code, after someone puts it into a snippet, is buggy for some reason. Here's one code fix: fixBorder() to tryBorder()
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Test</title>
<style type="text/css">
.item {
position: absolute;
height: auto;
opacity: 1;
}
.mouseover { border:1px dashed green; }
</style>
<script>
function id(name) { return document.getElementById(name); }
function tryBorder() {
var w1 = id("part-1").style.width.replace("px", "");
var h1 = id("part-1").style.height.replace("px", "");
var l1 = id("part-1").style.left.replace("px", "");
var t1 = id("part-1").style.top.replace("px", "");
var w2 = id("part-2").style.width.replace("px", "");
var h2 = id("part-2").style.height.replace("px", "");
var l1 = id("part-2").style.left.replace("px", "");
var t1 = id("part-2").style.top.replace("px", "");
// "math" for the group size and position
var wOverlay = l2 - w1;
var hOverlay = t2 - h1;
var wg = w1 + w2 - wOverlay;
var hg = h1 + h2 - hOverlay;
var lg = ( l1 < l2 ) ? l1 : l2;
var tg = ( h1 < h2 ) ? h1 : h2;
// ok, now how to I apply that math? is it easy?
id('group').onmouseover = function(event) {
alert("on mouseover");
if (! event.shiftKey) elem.classList.add('mouseover');
else elem.classList.remove('mouseover');
}
id('group').style.left = lg + "px";
id('group').style.top = hg + "px";
id('group').style.width = width + "px";
id('group').style.height = height + "px";
}
</script>
</head>
<body onload="tryBorder();">
<div id="group" style="border:5px solid red">
<img id="part-1" class="item" src="https://dummyimage.com/640x4:3/">
<img id="part-2" class="item" src="https://dummyimage.com/300/09f.png/fff">
</div>
</body>
</html>

if i understood u try this code
function id(name) { return document.getElementById(name); }
function tryBorder() {
var w1 = id("part-1").style.width.replace("px", "");
var h1 = id("part-1").style.height.replace("px", "");
var l1 = id("part-1").style.left.replace("px", "");
var t1 = id("part-1").style.top.replace("px", "");
var w2 = id("part-2").style.width.replace("px", "");
var h2 = id("part-2").style.height.replace("px", "");
var l1 = id("part-2").style.left.replace("px", "");
var t1 = id("part-2").style.top.replace("px", "");
// "math" for the group size and position
var wOverlay = l2 - w1;
var hOverlay = t2 - h1;
var wg = w1 + w2 - wOverlay;
var hg = h1 + h2 - hOverlay;
var lg = ( l1 < l2 ) ? l1 : l2;
var tg = ( h1 < h2 ) ? h1 : h2;
// ok, now how to I apply that math? is it easy?
id('group').onmouseover = function(event) {
alert("on mouseover");
if (! event.shiftKey) elem.classList.add('mouseover');
else elem.classList.remove('mouseover');
}
id('group').style.left = lg + "px";
id('group').style.top = hg + "px";
id('group').style.width = width + "px";
id('group').style.height = height + "px";
}
#group{
border:5px solid red;
position: relative;
max-width: 100%;
height: 600px;
}
.item1 {
position: absolute;
height: auto;
opacity: 1;
max-width: 100%;
}
.item2 {
position: absolute;
height: auto;
opacity: 1;
max-width: 100%;
}
.mouseover { border:1px dashed green; }
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Test</title>
</head>
<body>
<div id="group">
<img id="part-1" class="item1" src="https://dummyimage.com/640x4:3/">
<img id="part-2" class="item2" src="https://dummyimage.com/300/09f.png/fff">
</div>
</body>
</html>

Related

How do I dynamically create equally sized divs to fill the screen?

I've made an interactive 16x16 grid, who's divs grown and shrink based on screen size.
let x = 0;
let container = document.getElementById("container");
document.addEventListener('DOMContentLoaded', function() {
createLongContainers();
let longContainers = document.querySelectorAll(".longContainer");
createBoxes(longContainers);
});
function createLongContainers() {
for (var i = 0; i < 16; i++) {
let div = document.createElement('div');
div.className = "longContainer";
div.style.display = "flex";
div.style.flexDirection = "row"
var lcHeight = ((100 / 16) + "%");
div.style.height = lcHeight;
div.style.width = "100vh";
container.appendChild(div);
}
}
function createBoxes(longContainers) {
longContainers.forEach((div) => {
for (var i = 0; i < 16; i++) {
let box = document.createElement('div');
box.className = "gridSquare";
let boxWidth = ((100 / 16) + "%");
box.style.height = "100%";
box.style.width = boxWidth;
box.style.backgroundColor = "black";
box.onmouseover = function() {
var randomColor = Math.floor(Math.random() * 16777215).toString(16);
box.style.transitionDuration = "0s";
box.style.backgroundColor = "#" + randomColor;
};
box.onmouseout = function() {
box.style.transitionDuration = "3s";
box.style.backgroundColor = "black";
}
div.appendChild(box);
}
});
}
#container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
width: 100vw;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Colorful Grid</title>
<link rel="stylesheet" href="style.css">
<script src="script.js" defer></script>
</head>
<body style="margin: 0;">
<div id="container"></div>
<!-- Removes white border around page-->
</body>
</html>
I can't figure out how to fill the screen with this grid, while maintaining their square shape and ability to shrink in relation to the screen size.
For example, when I change
div.style.width = "100vh";
to
div.style.width = "100vw";
and add more boxes so they aren't stretched, they lose their ratio when the screen size is changed.
I know I need to dynamically create fixed size divs based on the current screen size, but I can't figure out how.
I chanegd your script a little and sued CSS-Grid over Flexbox which will make everythign easier IMHO. Also you onyl need to run 1 script as it includes 256 boxes (16x16) instead of 16 rows that then again include 16 child boxes.
I also removed the style-statements from JS completely. I add the styles through CSS to shorten the JS code.
Then I used aspect-ratio to maintain a square-size. Alternativly you can hardcode it.
Then I used media queries within CSS to check if the screen size is in landscape or in portrait-mode and set the width of the squares to either to 1frorcalc(100vh / 16)`.
Last but not least I use overflow: hidden on the container to hide the elements that would not fit the viewport anymore. That is the onyl way to fill the entire screen without breaking the aspect-ration of the boxes.
let x = 0;
let container = document.getElementById("container");
document.addEventListener('DOMContentLoaded', function() {
createBoxes();
});
function createBoxes() {
document.querySelectorAll('#container').forEach((div) => {
for (var i = 0; i < 256; i++) {
let box = document.createElement('div');
box.className = "gridSquare";
box.onmouseover = function() {
var randomColor = Math.floor(Math.random() * 16777215).toString(16);
box.style.transitionDuration = "0s";
box.style.backgroundColor = "#" + randomColor;
};
box.onmouseout = function() {
box.style.transitionDuration = "3s";
box.style.backgroundColor = "black";
}
div.appendChild(box);
}
});
}
#container {
display: grid;
height: 100vh;
width: 100vw;
overflow: hidden;
}
#media only screen and (orientation: portrait) {
#container {
grid-template-columns: repeat(16, calc(100vh / 16));
}
}
#media only screen and (orientation: landscape) {
#container {
grid-template-columns: repeat(16, 1fr);
}
}
.gridSquare {
aspect-ratio: 1 / 1;
background-color: black;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Colorful Grid</title>
<link rel="stylesheet" href="style.css">
<script src="script.js" defer></script>
</head>
<body style="margin: 0;">
<div id="container"></div>
<!-- Removes white border around page-->
</body>
</html>
I saw your comment that you wanted to use 20px squares. I changd the script and CSS to adjust for that. I got rid of the media queries and changed the number of columns to repeat(auto-fill, minmax(20px, 1fr)); That will include as many columns of at least 20px and fill them with as many as possible. Then it upsize the columns to leave no white-space.
To create as many boxes as needed you can create a ridicolous number of boxes. However this will cause serious performance issues.
Therefore, I wrote this little script:
var container = document.querySelector('#container');
var containerWidth = Math.floor(container.offsetWidth / 20),
containerHeight = Math.ceil(container.offsetHeight / 20);
var squareAmount = containerWidth * containerHeight;
This script get the width and height of the viewport. It divides both by 20. The width can be rounded down but the height must be rounded up to allow the overflow. Then I multiply both values and get the sum of them. That sum is used in the loop as target so it will only create as many boxes as actually needed:
let x = 0;
let container = document.getElementById("container");
document.addEventListener('DOMContentLoaded', function() {
createBoxes();
});
function createBoxes() {
document.querySelectorAll('#container').forEach((div) => {
var container = document.querySelector('#container');
var containerWidth = Math.floor(container.offsetWidth / 20),
containerHeight = Math.ceil(container.offsetHeight / 20);
var squareAmount = containerWidth * containerHeight;
for (var i = 0; i < squareAmount; i++) {
let box = document.createElement('div');
box.className = "gridSquare";
box.onmouseover = function() {
var randomColor = Math.floor(Math.random() * 16777215).toString(16);
box.style.transitionDuration = "0s";
box.style.backgroundColor = "#" + randomColor;
};
box.onmouseout = function() {
box.style.transitionDuration = "3s";
box.style.backgroundColor = "black";
}
div.appendChild(box);
}
});
}
#container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(20px, 1fr));
height: 100vh;
width: 100vw;
overflow: hidden;
}
.gridSquare {
aspect-ratio: 1 / 1;
background-color: black;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Colorful Grid</title>
<link rel="stylesheet" href="style.css">
<script src="script.js" defer></script>
</head>
<body style="margin: 0;">
<div id="container"></div>
<!-- Removes white border around page-->
</body>
</html>
Is this what you want?
let x = 0;
let container = document.getElementById("container");
document.addEventListener('DOMContentLoaded', function () {
createLongContainers();
let longContainers = document.querySelectorAll(".longContainer");
createBoxes(longContainers);
});
function createLongContainers() {
for (var i = 0; i < 16; i++) {
let div = document.createElement('div');
div.className = "longContainer";
div.style.display = "flex";
div.style.flexDirection = "row"
div.style.justifyContent = "space-around"
var lcHeight = "100%";
div.style.height = lcHeight;
div.style.width = "100%";
container.appendChild(div);
}
}
function createBoxes(longContainers) {
longContainers.forEach((div) => {
for (var i = 0; i < 16; i++) {
let box = document.createElement('div');
box.className = "gridSquare";
box.style.backgroundColor = "black";
box.onmouseover = function () {
var randomColor = Math.floor(Math.random()*16777215).toString(16);
box.style.transitionDuration = "0s";
box.style.backgroundColor = "#" + randomColor;
};
box.onmouseout = function () {
box.style.transitionDuration = "3s";
box.style.backgroundColor = "black";
}
div.appendChild(box);
}
});
}
#container{
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
width: 100%;
}
.gridSquare {
height: calc(100vh / 16);
aspect-ratio: 1/1;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Colorful Grid</title>
<link rel="stylesheet" href="style.css">
<script src="script.js" defer></script>
</head>
<body style="margin: 0;"> <div id="container"></div><!-- Removes white border around page-->
</body>
</html>
Also try resizing it, it looks interesting because of the transition.

Background of absolutely positioned div is larger than expected (seemingly larger than its size indicates)

Below is a simplified example of code in a project I'm working on. Can you please help me understand and resolve, why the background of the g div, appears higher up and further left, when it's top is 10px, and it's left is 10px, just like p-1, the image inside it?
So, once again, why does the background extend higher than the 640x480 image, and why does it extend further to the left. Please note the console.log statements to help debug -- there should be nothing "fancy here", meaning why doesn't everything just start/appear at left, top: 10px, 10px
var toggle = false;
function id(name) { return document.getElementById(name); }
function run() {
id('p-1').style.left = "10px"
id('p-1').style.top = "10px"
id('p-2').style.left = "660px"
id('p-2').style.top = "500px"
var w1 = id("p-1").clientWidth;
var h1 = id("p-1").clientHeight;
var l1 = id("p-1").style.left.replace("px", "");
var t1 = id("p-1").style.top.replace("px", "");
var w2 = id("p-2").clientWidth;
var h2 = id("p-2").clientHeight;
var l2 = id("p-2").style.left.replace("px", "");
var t2 = id("p-2").style.top.replace("px", "");
// "math" for the g size and position
var wOverlay = l2 - w1;
var hOverlay = t2 - h1;
var wg = w1 + w2 + wOverlay;
var hg = h1 + h2 + hOverlay;
var lg = ( l1 < l2 ) ? l1 : l2;
var tg = ( t1 < t2 ) ? t1 : t2;
console.log("p-1: (l,t)=(" +l1+ "," +t1+ "), (w, h) = (" +w1+ "," +h1+ ").");
console.log("p-2: (l,t)=(" +l2+ "," +t2+ "), (w, h) = (" +w2+ "," +h2+ ").");
console.log("g: (l,t)=(" +lg+ "," +tg+ "), (w, h) = (" +wg+ "," +hg+ ").");
id('g').style.left = lg + "px";
id('g').style.top = tg + "px";
id('g').style.width = wg + "px";
id('g').style.height = hg + "px";
console.log("div (l,t)=(" +id('g').style.left+ "," +id('g').style.top+ "), (width, height) = (" +id('g').style.width+ "," +id('g').style.height+ ").");
}
html, body {
height: 100%;
margin: 0;
padding: 0;
}
.item {
position: absolute;
height: auto;
opacity: 1;
margin: 0;
padding: 0;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Div</title>
</head>
<body onload="run();">
<div class="item" id="g" style="background-color:gold;">
<img id="p-1" class="item" src="https://dummyimage.com/640x4:3/">
<img id="p-2" class="item" src="https://dummyimage.com/300/09f.png/fff">
</div>
</body>
</html>

Dom html javascript about onclick

I want to generate five image imgs first in left side, then remove the lastchild of it and copy the rest to the right side. If user clicks the extra img in left side, then clear all and generate more 5(10) img in left and copy 9 to the right side, and so on. If user clicks the wrong place, alert ("game over").Here is my code:
<html>
<head>
<style>
img{
position: absolute;
}
div{
position: absolute;
width: 500px;
height: 500px;
}
#rightSide { left: 500px;
border-left: 1px solid black;
}
</style>
<script>
var numberOfFaces = 5;
function generateFaces(){
var theLeftSide = document.getElementById("leftSide");
for (var i = 0; i < numberOfFaces; i++){
var img = document.createElement("img");
img.src = "smile.png";
var randomTop = Math.random() * 400;
var randomLeft = Math.random() * 400;
img.style.top = randomTop + "px";
img.style.left = randomLeft + "px";
theLeftSide.appendChild(img);
}
var theRightSide = document.getElementById("rightSide");
leftSideImages = theLeftSide.cloneNode(true);
leftSideImages.removeChild(leftSideImages.lastChild);
document.getElementById("rightSide").appendChild(leftSideImages);
var theBody = document.getElementByTagName("body")[0];
theLeftSide.lastChild.onclick = function nextLevel(event){
event.stopPropagation();
while (theBody.firstChild){
theBody.removeChild(theBody.firstChild);
}
numberOfFaces += 5;
generateFaces();
}
theBody.onclick = function gameover(){
alert("Game Over");
thBody.onclick = null;
theLeftSide.lastChild.onclick = null;
}
}
window.onload = generateFaces;
</script>
</head>
<body>
<h1>Matching Game</h1>
<p>click on the extra smiling face on the left</p>
<div id = "leftSide">
</div>
<div id = "rightSide">
</div>
</body>
</html>
I could generate and clone at first time, but when I click, nothing happens, so what is the problem?
This may be a typing error.
var theBody = document.getElementsByTagName("body")[0];
your code: var theBody = document.getElementByTagName("body")[0];
I suggest to use a good editor for html. I fixed the error with Jetbrain phpStorm but better ones may exist.
Bellow is a modified version that worked for me. Notice that in this version I added the events on all children instead of the whole document body. I don't know but for me it feels more accurate not to end the game on a user clicks on a white space for example.
<html>
<head>
<style>
img{
position: absolute;
}
div{
position: absolute;
width: 500px;
height: 500px;
}
#rightSide { left: 500px;
border-left: 1px solid black;
}
</style>
<script>
var numberOfFaces = 5;
var theBody;
var theLeftSide;
var theRightSide;
function generateFaces(){
theBody = document.getElementsByTagName("body")[0];
theLeftSide = document.getElementById("leftSide");
theRightSide = document.getElementById("rightSide");
for (var i = 0; i < numberOfFaces; i++){
var img = document.createElement("img");
img.src = "smile.png";
var randomTop = Math.random() * 400;
var randomLeft = Math.random() * 400;
img.style.top = randomTop + "px";
img.style.left = randomLeft + "px";
if(theLeftSide != null)
theLeftSide.appendChild(img);
else
{
alert("Game Over");
return;
}
}
var leftSideImages = theLeftSide.cloneNode(true);
leftSideImages.removeChild(leftSideImages.lastChild);
document.getElementById("rightSide").appendChild(leftSideImages);
addEvents();
}
function addEvents(){
for(var i=0; i < theLeftSide.childNodes.length; i++){
theLeftSide.childNodes[i].onclick = nextLevel;
}
}
function removeEvents(){
for(var i=0; i < theLeftSide.childNodes.length; i++){
theLeftSide.childNodes[i].onclick = null;
}
}
function nextLevel(event){
if(this == theLeftSide.lastChild){
event.stopPropagation();
theLeftSide.innerHTML = "";
theRightSide.innerHTML = "";
numberOfFaces += 5;
generateFaces();
}
else
{
alert("Game Over");
removeEvents();
}
}
window.onload = generateFaces;
</script>
</head>
<body>
<h1>Matching Game</h1>
<p>click on the extra smiling face on the left</p>
<div id = "leftSide">
</div>
<div id = "rightSide">
</div>
</body>
</html>

Why do the elements not appear in random places but they are staying aligned on top of the div?

The code is supposed to generate 5 elements one by one so that when the page is downloaded all we`ll see 5 elements (newFace) in random places.
This code generates all 5 elements but they are staying aligned one by one instead of appearing in random position as wished
function generate_faces() {
var theLeftSide = document.getElementById("leftSide");
var number_of_faces = 0;
while (number_of_faces < 5){
var top_position = Math.floor(Math.random()*300);
var left_position = Math.floor(Math.random()*300);
newFace = document.createElement("img");
newFace.setAttribute(
"src",
"http://home.cse.ust.hk/~rossiter/mooc/matching_game/smile.png"
);
newFace.style.top = top_position+"px";
newFace.style.left = left_position+"px";
theLeftSide.appendChild(newFace);
number_of_faces = number_of_faces + 1;
}
}
Try this.
<!DOCTYPE html>
<html>
<head></head>
<style>
html, body, leftSide {
width: 100%;
height: 100%;
position: relative;
}
#leftSide {
position: relative;
}
#leftSide img {
position: absolute;
}
</style>
<body onclick="generate_faces()">
<div id="leftSide">
</div>
</body>
</html>
<script>
function generate_faces() {
var theLeftSide = document.getElementById("leftSide");
var number_of_faces = 0;
while (number_of_faces < 5){
var top_position = Math.floor(Math.random()*300);
var left_position = Math.floor(Math.random()*300);
newFace = document.createElement("img");
newFace.setAttribute(
"src",
"http://home.cse.ust.hk/~rossiter/mooc/matching_game/smile.png"
);
newFace.style.top = top_position+"px";
newFace.style.left = left_position+"px";
theLeftSide.appendChild(newFace);
number_of_faces = number_of_faces + 1;
}
}
</script>

How to clone the contents of a div into another div with JavaScript?

I want to clone the images of the div leftSide into the div rightSide. On each click on the body the images on the left div should be cloned into the right div. But I can't get the result with the code I'm doing. Is there any mistake in my code? I want to use JavaScript.
Here's my code:
var theLeftSide = document.getElementById("leftSide");
var width = 500; var height = 500;
top_position = 0; var left_position = 0,
var numberOfFaces = 5;
var theRightSide = document.getElementById("rightSide");
var leftSideImages = theLeftSide.cloneNode(true);
document.getElementById("rightSide").appendChild(leftSideImages);
for (var i = 0; i < 5; i++) {
createElement(i);
numberOfFaces += 5;
function createElement() {
var image = document.createElement('img');
image.src = "smile.png";
image.style.position = 'absolute';
image.style.top = top_position + "px";
image.style.left = left_position + "px";
theLeftSide.appendChild(image);
top_position = Math.random() * 500 ;
left_position = Math.random() * 500 ;
Here is a simple example that clones an HTMLElement in vanilla javascript:
additional information can be found in MDN
function CloneCtrl() {
'use strict';
var self = this;
self.source = document.querySelector('.source');
self.target = document.querySelector('.target');
self.cloneSource = function(event) {
var clone = self.source.cloneNode(true);
self.target.appendChild(clone);
}
document
.getElementById('cloneBtn')
.addEventListener('click', self.cloneSource)
;
}
document.addEventListener('DOMContentLoaded', CloneCtrl);
.source {
background: lightseagreen;
width: 100px;
height: 100px;
line-height: 100px;
overflow: hidden;
margin: 5px;
display: inline-block;
text-align: center;
color: #fff;
}
.target {
border: 1px solid lightcoral;
min-height: 110px;
}
<div><button id="cloneBtn">Clone Source</button></div>
<div class="source">SOURCE</div>
<hr>
<div class="target"></div>
With jQuery, you can do it kike that:
$('#div2').html($('#div1').html());
which is found from this question: Copy the content of a div into another div.
You don't actually provide many details, thus the best I can post, hope it helps!!
you could simply try this if you have second div on page.
document.getElementById("SecondDv").innerHTML = document.getElementById("FirstDv").innerHTML;
This will copy whatever is there in FirstDiv to Second. lmk if it works.

Categories