variable holding style value can't be changed - javascript

I am curious about a simple problem. Here is the code:
var square = document.getElementById('square')
var left = square.style.left
function moveNoVariable() {
square.style.left = "100px" // works
}
function moveWithVariable() {
left = "100px" // doesn't work
}
moveNoVariable()
#square {
width: 20px;
height: 20px;
border: 1px solid black;
background-color: red;
position: relative;
}
<div id="square"></div>
I am just wondering why the style won't change if I use "left" even though it is storing the correct value.
Thanks.

square.style.left is a string. If you put a string into a variable, the variable will store a copy of the given string. If you put an object into a variable, the variable will refer to the original object. So you could do this for example:
var square = document.getElementById('square')
var style = square.style
function moveNoVariable() {
square.style.left = "100px" // works
}
function moveWithVariable() {
style.left = "100px" // will work
}

Related

How to change opacity of element when scrolled to bottom within media query

I just want to ask. I want to make the product image thumbnail in shopify disappear when I scrolled down to bottom of the page, and I want a bit of transition with it.. I really can't figure out how to do this..
Here's my code..
https://jsfiddle.net/vsLdz4qb/1/
function myFunction(screenWidth) {
if (screenWidth.matches) { // If media query matches
window.onscroll = function(ev) {
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
document.getElementByClass("product-single__thumbnails").style.transition = "0.65s";
document.getElementByClass("product-single__thumbnails").style.opacity = 0;
}
};
}
}
let screenWidth = window.matchMedia("(min-width: 750px)");
myFunction(screenWidth); // Call listener function at run time
screenWidth.addListener(myFunction)
Thank you so much in advance!
The correct document method is document.getElementsByClassName and since it returns an array you need the first element of it so change this:
document.getElementByClass("product-single__thumbnails").style.transition = "0.65s";
document.getElementByClass("product-single__thumbnails").style.opacity = 0;
to:
document.getElementsByClassName("product-single__thumbnails")[0].style.transition = "0.65s";
document.getElementsByClassName("product-single__thumbnails")[0].style.opacity = 0;
You can read more about the method here
You should use getElementsByClassName in place of getElementByClass(This is not correct function)
and this will return an array like structure so you need to pass 0 index, if only one class available on page.
or you can try querySelector(".product-single__thumbnails");
and for transition, you can define that in your .product-single__thumbnails class like: transition: opacity .65s linear; - use here which property, you want to animate.
<!-- [product-image] this is for product image scroll down disappear -->
function myFunction(screenWidth) {
if (screenWidth.matches) { // If media query matches
window.onscroll = function(ev) {
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
document.getElementsByClassName("product-single__thumbnails")[0].style.opacity = 0;
}
};
}
}
let screenWidth = window.matchMedia("(min-width: 350px)");
myFunction(screenWidth); // Call listener function at run time
screenWidth.addListener(myFunction)
body {
margin:0;
height: 1000px;
}
.product-single__thumbnails {
background-color: red;
color: white;
width: 50px;
height: 50px;
position: fixed;
transition: opacity .65s linear;
border-radius: 4px;
margin: 20px;
text-align: center;
}
<div class="product-single__thumbnails">
<p>red</p>
</div>

JavaScript innerHTML for few seconds

I followed a tutorial on how to build basic games by using JS/HTML and now I am expanding it. Game here
press space to fire
press the right arrow to turn right and the left one to turn left
I was able to get the location of the collision between an enemy and a missile and add a new #explosion to the html by using innerHTML. I am confused how I can be able to remove the explosion after 1 second.
const explosion = (topEn, leftEn) => {
document.getElementById('explosions').innerHTML +=
`
<div id="explosion" style='
left:${leftEn}px;
top: ${topEn}px;
'></div>
`;
}
#explosion{
background-image: url("assets/explosion.png");
height: 50px;
width: 50px;
position: absolute;
}
Without the rest of your code it's hard to give you an exact show, but this is largely what my comment was referring to.
const explosion = (topEn, leftEn, delay = 1000) => {
const div = document.createElement('div');
div.id = 'explosion';
div.style.top = topEn + 'px';
div.style.left = leftEn + 'px';
document.getElementById('explosions').append(div);
setTimeout(() => {
div.remove()
}, delay);
}
explosion(200, 200, 1000);
setTimeout(()=> explosion(300, 400, 800), 500)
#explosion {
background-image: url("assets/explosion.png");
height: 50px;
width: 50px;
position: absolute;
/* I added this to be able to see the divs*/
background-color: red;
}
body, html, #explosions {
height: 100%;
width: 100%;
}
<div id="explosions"></div>
Notes:
If you are going to perhaps have multiple elements of the same type (i.e.) explosions in the DOM at the same time you should move to using a class instead of an ID. IDs are unique identifiers, so while you can have multiple elements with the same ID, it will lead you to unexpected results. If your game will be able to have more than 1 explosion going at any given time, move #explosion to .explosion

Determine if element is behind another

Is there a way to determine whether elementA is "behind" another element and thus elementA would not be visible to the user?
Obviously it's possible to do with stacking context, but the thing is that we do not know which elements we should be looking at. Therefore we would have to iterate through all the elements in DOM and perform stacking context comparison for multiple elements. That is not good in terms of performance.
Here's a jsfiddle. So is there a way to determine that #hidden-element is not visible to the user, because another element is rendered on top of it?
https://jsfiddle.net/b9dek40b/5/
HTML:
<div id="covering-element"></div>
<div>
<div id="hidden-element"></div>
</div>
Styles:
#covering-element {
position: absolute;
width: 100px;
height: 100px;
background: darksalmon;
text-align: center;
}
#hidden-element {
width: 25px;
height: 25px;
background: deeppink;
}
Our solution was to use couple things to determine whether the element is visible and not behind any other elements. Here's the methods we used.
window.getComputedStyle to check visibility:hidden and display:none
document.elementFromPoint from multiple points. Most common cases could probably be handled by checking all the corners. Though we needed more points to get more robust results. Corner coordinates can be easily checked with Element.getBoundingClientRect()
https://jsfiddle.net/k591Lbwu/27/
HTML
<div id="covering-element"></div>
<div>
<div id="hidden-element"></div>
</div>
<button style="margin-top:100px">Check visibility</button>
CSS
#covering-element {
position: absolute;
width: 100px;
height: 100px;
background: darksalmon;
text-align: center;
}
#hidden-element {
width: 25px;
height: 25px;
background: deeppink;
}
JavaScript
document.querySelector('button').addEventListener('click', function() {
const element = document.getElementById('hidden-element')
alert('Visible = '+isVisible(element))
})
function isVisible(element) {
if(!isVisibleByStyles(element)) return false
if(isBehindOtherElement(element)) return false
return true
}
function isVisibleByStyles(element) {
const styles = window.getComputedStyle(element)
return styles.visibility !== 'hidden' && styles.display !== 'none'
}
function isBehindOtherElement(element) {
const boundingRect = element.getBoundingClientRect()
// adjust coordinates to get more accurate results
const left = boundingRect.left + 1
const right = boundingRect.right - 1
const top = boundingRect.top + 1
const bottom = boundingRect.bottom - 1
if(document.elementFromPoint(left, top) !== element) return true
if(document.elementFromPoint(right, top) !== element) return true
if(document.elementFromPoint(left, bottom) !== element) return true
if(document.elementFromPoint(right, bottom) !== element) return true
return false
}

CreatePopup replacement

Using regular JavaScript or JQuery I want to replace the createPopup() method like done in this post:
A universal createPopup() replacement?
but I want to use a Div instead of an iFrame. I don't need anything fancy just a simple div which can be styled.
The problem with using a Div is that I have a lot of existing code like this which I would like to remain untouched e.g.
var popup = window.createPopup();
oPopup.document.body.innerHTML = "Click outside <strong>popup</strong> to close.";
In the new createPopup() method below, is there a way to return an object that has the properties document.body.innerHTML to style the Div and the existing code can remain untouched.
if(!window.createPopup){
window.createPopup = function() {
// TODO return div object
}
}
You can use javascript setters and getters in combination with defineProperties to pull off what you are trying to do.
if(!window.createPopup){
window.createPopup = (function() {
// build our object
var o = {
document: {
body: {
_innerHTML: ''
}
}
};
// build the popup
o.document.body._outer = document.createElement('div');
o.document.body._inner = document.createElement('div');
o.document.body._outer.className = 'modal';
o.document.body._inner.className = 'inner';
// attach popup
o.document.body._outer.appendChild(o.document.body._inner);
document.body.appendChild(o.document.body._outer);
// add a property for innerHTML
Object.defineProperties(o.document.body, {
'innerHTML': {
get: function () { return this._innerHTML; },
set: function (x) {
this._innerHTML = x;
this._inner.innerHTML = this._innerHTML;
}
}
});
// return the object
return o;
});
}
var oPopup = window.createPopup();
oPopup.document.body.innerHTML = "Click outside <strong>popup</strong> to close.";
.modal {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: rgba(0,0,0,0.5);
}
.modal .inner {
padding: 2em;
background: #fff;
border: 1px solid #eee;
display: inline-block;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}

Potential function overloading in javascript: naming issue

I am new to Javascript but I was able to piece together something to create a random background image on page load. This was successfully used for a Div object on the page.
Since this worked well, I wanted to use this command again for a second Div object on the same page. Both Divs had separate CSS style names so I thought this would be fine. However as soon as I use both commands together, only one will work.
I assumed it was an overloading problem, but I tried renaming everything I could and it still hasn't solved it. Is there something else I need to rename that I'm missing or do I need to frame the two separate commands differently?
Below is the JS code, CSS and HTML:
Thanks in advance!
/*! random background image 2*/
window.onload = function frontimage() {
var thediv2 = document.getElementById("topimg");
var imgarray2 = new Array("f1.svg", "f2.svg");
var spot2 = Math.floor(Math.random()* imgarray2.length);
thediv2.style.background = "url(img/f-img/"+imgarray2[spot2]+")";
thediv2.style.backgroundSize = "70%";
thediv2.style.backgroundAttachment = "fixed";
thediv2.style.backgroundRepeat = "no-repeat";
thediv2.style.zIndex = "2";
thediv2.style.backgroundColor = "rgba(255,204,255,0.5)";
}
/*! random background image 1*/
window.onload = function backimage() {
var thediv = document.getElementById("imgmain");
var imgarray = new Array("b1.jpg", "b2.jpg", "b3.jpg", "b4.jpg", "b5.jpg");
var spot = Math.floor(Math.random()* imgarray.length);
thediv.style.background = "url(img/b-img/"+imgarray[spot]+")";
thediv.style.backgroundSize = "100%";
thediv.style.backgroundAttachment = "fixed";
thediv.style.backgroundRepeat = "no-repeat";
thediv.style.zIndex = "1";
}
#bigimg {
clear: both;
float: left;
margin-left: 0;
width: 100%;
display: block;
}
#imgmain {
background: 50% 0 no-repeat fixed;
z-index: 1;
width: 100%;
}
#topimg {
z-index: 2;
position: absolute;
background-image: url(../img/f-img/f2.svg);
background-repeat: no-repeat;
background-position: 50% -25%;
background-size:contain;
width: 100%;
margin: auto;
padding: 0;
}
<div id="bigimg">
<section id="imgmain"></section>
<section id="topimg"></section>
</div>
With addEventListener, you can add as many event handlers as you want.
window.addEventListener('load', function frontimage() {
// ...
});
window.addEventListener('load', function backimage() {
// ...
});
You are overriding your first window.onload by reassigning the callback function.
Try this:
window.onload = function() {
frontimage();
backimage();
}

Categories