DOM Manipulation Click Mouse Event - javascript

I was trying to change the color of the background of the web page with a mouse click, below are the lines for the same:
let bodyvar = document.querySelector('body');
bodyvar.addEventListener("click",generate);
function generate(){
bodyvar.style.backgroundColor = "red";
}
When I test individual lines in console it is selecting the body and the function and everything works correctly individually but not on the actual page.
I have just started leaning JS so am not sure what am missing here, will I also need to consider the co-ordinates that the mouse clicks on?

I suspect that the <body></body> is empty. Add some content, or define the width and height.
let bodyvar = document.querySelector('body');
bodyvar.style.minWidth = "100vw";
bodyvar.style.minHeight = "100vh";
bodyvar.addEventListener("click",generate);
function generate(){
bodyvar.style.backgroundColor = "red";
}
Alternatively, I can use <HTML> instead of <body>.
let bodyvar = document.querySelector('html');
bodyvar.addEventListener("click",generate);
function generate(){
bodyvar.style.backgroundColor = "red";
}

Related

Get the bounding box of an SVG element [duplicate]

I'm trying to solve this problem for more than one day now, but I can't find an answer. My problem is that I need to scale an SVG image (responsive design). I need to manipulate the SVG code on the client side, so embedding it via img tag is not an option. Therefore I tried to use an inline image instead. However, to scale it properly it seems that I need to set the viewBox property. The SVG files are generated by some software which can't set the bounding box on it's own, so my idea was to use JavaScript for that purpose.
The problem is that my software uses various tab controls from a library which I can't modify. I can't just get the bounding box, because it's not rendered initially and therefore I just get back zeros (in Chrome) or error messages (in Firefox).
What I need is a way to get the size of the bounding box without actually rendering the object. It is not possible to manipulate the display parameter, which the library uses to show and hide tabs.
Any ideas?
One idea was to copy the SVG into another, visible div, but I don't know if that would solve the problem. And I don't know how to do it.
Best regards
Based on the previous answers, I monkeypatched getBBox on my app init so it will transparently apply the hack.
Now I can call getBBox directly on any element, whether it's attached or not.
_getBBox = SVGGraphicsElement.prototype.getBBox;
SVGGraphicsElement.prototype.getBBox = function() {
var bbox, tempDiv, tempSvg;
if (document.contains(this)) {
return _getBBox.apply(this);
} else {
tempDiv = document.createElement("div");
tempDiv.setAttribute("style", "position:absolute; visibility:hidden; width:0; height:0");
if (this.tagName === "svg") {
tempSvg = this.cloneNode(true);
} else {
tempSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
tempSvg.appendChild(this.cloneNode(true));
}
tempDiv.appendChild(tempSvg);
document.body.appendChild(tempDiv);
bbox = _getBBox.apply(tempSvg);
document.body.removeChild(tempDiv);
return bbox;
}
};
you can clone it to a visible svg and then getBBox.
Add into you html:
<div style="position:absolute;left:-9999cm;top:-9999cm;visibility:hidden;">
<svg id="svg1" xmlns="http://www.w3.org/2000/svg"></svg>
</div>
Add into your javascript:
function getBBox(elem){
var svg1 = document.getElementById('svg1'), e = elem.cloneNode(true);
e.style.display = "inline";
svg1.appendChild(e);
var b = e.getBBox();
svg1.removeChild(e);
return b;
}
cuixiping's answer as a function:
function svgBBox (svgEl) {
let tempDiv = document.createElement('div')
tempDiv.setAttribute('style', "position:absolute; visibility:hidden; width:0; height:0")
document.body.appendChild(tempDiv)
let tempSvg = document.createElementNS("http://www.w3.org/2000/svg", 'svg')
tempDiv.appendChild(tempSvg)
let tempEl = svgEl.cloneNode(true)
tempSvg.appendChild(tempEl)
let bb = tempEl.getBBox()
document.body.removeChild(tempDiv)
return bb
}

Dynamically increasing font size

I would like to increase the font size of the paragraph as well as the font size of the number in the button.
I copied and pasted my sizer function from StackOverflow (a few alterations) and thought it would work and still can't get it to work. Can someone help?
Since I've spent so much time on just the first part, as a beginner programmer, I'm wondering what I am missing. Does anyone have any ideas from my code or their experience as to what I might be missing?
Thanks as always.
<html>
<button onclick='incrementer(); sizer()' id='count' value=0 />0</button>
<p id='test'>a</p>
<script>
clicks = 0
incrementer = function () {
clicks += 1
click = document.querySelector("#count").textContent = clicks;
click.innerHTML = document.getElementById("count").value = document.getElementById('test');
}
sizer = function changeFontSize() {
div = document.getElementById("test");
currentFont = div.style.fontSize.replace("pt", "");
div.style.fontSize = parseInt(currentFont) + parseInt(clicks) + "pt";
}
</script>
</html>
Some things here:
I woudn't append two functions to your onclick here. Just append one and call your second function from the first one that gets fired via onclick. That looks a lot more tidy
Don't forget to put var before every variable, without it's not valid JavaScript
I didn't quite understand what you tried with your currentFont variable, so I removed it. It's not necessary and causes the script to not working correctly
<html>
<button onclick='incrementer()' id='count' value=0 />0</button>
<p id='test'>a</p>
<script>
var clicks = 0;
var incrementer = function() {
clicks += 1;
var click = document.querySelector("#count").textContent = clicks;
click.innerHTML = document.getElementById("count").value = document.getElementById('test');
sizer();
}
var sizer = function changeFontSize() {
var div = document.getElementById("test");
div.style.fontSize = parseInt(clicks) + "pt";
}
</script>
</html>
Here's a from-scratch version that does what you're asking for. I'll point out a few things that I did to help you out.
https://codepen.io/anon/pen/VBPpZL?editors=1010
<html>
<body>
<button id="count">0</button>
<p id="test">
Lorem Ipsum is simply dummy text of the printing and typesetting industry.
</p>
</body>
</html>
JS:
window.addEventListener('load', () => {
const button = document.querySelector('#count');
const paragraph = document.querySelector('#test');
const startingFontSize = window.getComputedStyle(document.body, null)
.getPropertyValue('font-size')
.slice(0, 2) * 1;
let clicks = 0;
button.addEventListener('click', () => {
clicks++;
// this is a template literal
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
const fontSize = `${startingFontSize + clicks}px`;
button.innerHTML = clicks;
button.style.fontSize = fontSize;
paragraph.style.fontSize = fontSize;
});
});
The code runs when the page is loaded, so we attach an event listener on the window object listening for the load event.
We then store references to the button and the paragraph elements. These are const variables because their values won't change. This also limits their scope to the containing function.
We get the initial font size for the body element, because in this example we aren't explicitly setting a base font in css so we're just using the one for the document. getComputedStyle is a somewhat expensive operation, and in this case we only need to get it in the beginning because it won't change, so we also store it as a const. The value is returned as a string like "16px" but we need the number, hence the slice and multiplying by one to cast the string into a number. parseInt would also do the same thing.
Notice that clicks is defined with let. This means that the variable can be changed. var still works of course, but in modern practices its best to use const and let when declaring variables. This is partly because it forces you to think about what kind of data you're working with.
We add an event listener to the button element and listen for the click event. First, we increment the clicks variable. Then we declare fontSize using a template literal which adds our new clicks count to the startingFontSize and "px" to get a string.
Finally, the innerHTML value of the button element is updated. Then we update the fontStyle property for both elements.
The issue here is that there is no initial value for the fontSize of your <p> tag so div.style.fontSize returns an empty string.
You can use window.getComputedStyle instead of div.style.fontSize and you will get the current fontSize.
There is already a post explaining this method
https://stackoverflow.com/a/15195345/7190518
You don't have an initial font-size style on your <p> tag, so it div.style.fontSize is always empty. Also, best practice is to always use var when introducing new variables in javascript.
One good trick to help debugging things like these is to use console.log() at various points, and see whats coming out in your browser console. I used console.log(div.style.fontSize) and the answer became clear.
Working below after adding <p style='font-size:12px'>a</p>:
<html>
<button style='font-size:12px;' onclick='incrementer(); sizer()' id='count' value=0 />0</button>
<p id='test' style='font-size:12px;'>a</p>
<script>
var clicks = 0
incrementer = function () {
clicks += 1
click = document.querySelector("#count").textContent = clicks;
click.innerHTML = document.getElementById("count").value = document.getElementById('test');
}
var sizer = function changeFontSize() {
var div = document.getElementById("test");
var btn = document.getElementById("count");
var newSize = parseInt(div.style.fontSize.replace("pt", "")) + parseInt(clicks);
div.style.fontSize = newSize + "pt";
btn.style.fontSize = newSize + "pt";
}
</script>
</html>
I don't understand the logic of this solution, but you can simplify it avoiding to use a lot of var (anyway always prefer let or const if you don't need to change), using a single function and writing less code.
function increment(e){
const ctrl = document.getElementById('test');
let current = parseInt(e.dataset.size);
current += 1;
e.innerHTML = current;
e.dataset.size = current;
ctrl.style.fontSize = current + 'pt';
}
<button onclick="increment(this);" data-size="20">20</button>
<p id='test' style="font-size:20pt;">A</p>

make an absolute div hidden when something outside of it is clicked

I have some code for the function that runs when a button is clicked in my site:
function shadow() {
document.getElementById("overlay").style.visibility="visible";
document.getElementById("dim").style.visibility="visible";
document.getElementById("dim").onclick="document.getElementById('dim','overlay').style.visibility='hidden'";
}
With overlay being the overlay div that I want to be re-hide-able, and dim being the lower z-index dimmer over the entire page when the function runs.
The third line is my attempt at making it so that when an area outside of the overlay is clicked, the dim and overlay go away - help on that would be great!
The onclick property expects a function reference, not a string. In addition, the getElementById method only accepts a single id parameter, which means that only the first element id that you passed to it would be selected.
Based on the code you provided, it looks like you want something like this (live example):
function shadow() {
var overlay = document.getElementById('overlay');
var dim = document.getElementById('dim');
overlay.style.visibility = 'visible';
dim.style.visibility = 'visible';
dim.onclick = function() {
overlay.style.visibility = 'hidden';
dim.style.visibility = 'hidden';
};
}
Alternatively, you could also add a click event listener to document and then determine whether event.target is the #overlay element.
For instance, the following would work (live example):
document.addEventListener('click', function (event) {
var overlay = document.getElementById('overlay');
var dim = document.getElementById('dim');
if (event.target !== overlay && !event.target.closest('#overlay')) {
overlay.style.visibility = 'hidden';
dim.style.visibility = 'hidden';
}
});

GetBBox of SVG when hidden

I'm trying to solve this problem for more than one day now, but I can't find an answer. My problem is that I need to scale an SVG image (responsive design). I need to manipulate the SVG code on the client side, so embedding it via img tag is not an option. Therefore I tried to use an inline image instead. However, to scale it properly it seems that I need to set the viewBox property. The SVG files are generated by some software which can't set the bounding box on it's own, so my idea was to use JavaScript for that purpose.
The problem is that my software uses various tab controls from a library which I can't modify. I can't just get the bounding box, because it's not rendered initially and therefore I just get back zeros (in Chrome) or error messages (in Firefox).
What I need is a way to get the size of the bounding box without actually rendering the object. It is not possible to manipulate the display parameter, which the library uses to show and hide tabs.
Any ideas?
One idea was to copy the SVG into another, visible div, but I don't know if that would solve the problem. And I don't know how to do it.
Best regards
Based on the previous answers, I monkeypatched getBBox on my app init so it will transparently apply the hack.
Now I can call getBBox directly on any element, whether it's attached or not.
_getBBox = SVGGraphicsElement.prototype.getBBox;
SVGGraphicsElement.prototype.getBBox = function() {
var bbox, tempDiv, tempSvg;
if (document.contains(this)) {
return _getBBox.apply(this);
} else {
tempDiv = document.createElement("div");
tempDiv.setAttribute("style", "position:absolute; visibility:hidden; width:0; height:0");
if (this.tagName === "svg") {
tempSvg = this.cloneNode(true);
} else {
tempSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
tempSvg.appendChild(this.cloneNode(true));
}
tempDiv.appendChild(tempSvg);
document.body.appendChild(tempDiv);
bbox = _getBBox.apply(tempSvg);
document.body.removeChild(tempDiv);
return bbox;
}
};
you can clone it to a visible svg and then getBBox.
Add into you html:
<div style="position:absolute;left:-9999cm;top:-9999cm;visibility:hidden;">
<svg id="svg1" xmlns="http://www.w3.org/2000/svg"></svg>
</div>
Add into your javascript:
function getBBox(elem){
var svg1 = document.getElementById('svg1'), e = elem.cloneNode(true);
e.style.display = "inline";
svg1.appendChild(e);
var b = e.getBBox();
svg1.removeChild(e);
return b;
}
cuixiping's answer as a function:
function svgBBox (svgEl) {
let tempDiv = document.createElement('div')
tempDiv.setAttribute('style', "position:absolute; visibility:hidden; width:0; height:0")
document.body.appendChild(tempDiv)
let tempSvg = document.createElementNS("http://www.w3.org/2000/svg", 'svg')
tempDiv.appendChild(tempSvg)
let tempEl = svgEl.cloneNode(true)
tempSvg.appendChild(tempEl)
let bb = tempEl.getBBox()
document.body.removeChild(tempDiv)
return bb
}

Appending to body with javascript

I have an assignment to make several bugs fly around the screen randomly, but I'm having problems getting divs to be added to the html body through javascript.
<head>
<title>Fly little bug! Fly!</title>
<script type="text/javascript">
/* <![CDATA[ */
var numBugs = 0;
var body = document.getElementsByTagName("body");
function bug(startX, startY, xSpeed, ySpeed){
var self = this;
this.xPos = startX;
this.yPos = startY;
this.xSpeed = xSpeed;
this.ySpeed = ySpeed;
this.divId = "bug" + numBugs;
this.div = document.createElement("div");
this.div.innerHTML = "test";
body.appendChild(self.div);
this.fly = function(){
self.xPos += self.xSpeed;
self.yPos += self.ySpeed;
}
this.fly();
this.flyInterval = setInterval(function(){ self.fly(); },5000);
numBugs++;
}
/* ]]> */
</script>
</head>
<body onload = "var bug1 = new bug(10, 20, 5, 3);">
</body>
</html>
I can see two problems.
The getElementsByTagName function returns an array of elements. You have to be explicit that you want the first element of the array.
var body = document.getElementsByTagName("body")[0];
You're essentially saying "give me all the tags in the document of type 'body'". It gives you a list of tags, and you have to get the first one even though there should only be one "body" in any HTML document. The [0] in the code above gives you the first one.
You are trying to access the body before it's created. The <script> occurs in the document before the <body> tag, so at the time the script is executed, the body doesn't exist. You need to move the call to getElementsByTagName inside the bug() function.
document.body.innerHTML += '<div>Div Content</div>';
Look into jQuery if you want to make simple DOM manipulation easier on yourself.

Categories

Resources