How to conditionally apply different backgrounds to a canvas - javascript

The code shown here may be useful to others: It shows the solution I came up with to a requirement I had to, conditionally, apply different background images to a canvas. Questions on how to achieve this or variations of this have been asked here before.
(Sorry for my botched editing. I had originally posted this as a question, then, while reading my posted code, the answer dawned on me, so I removed that part of the post. I didn't realise at the time that there were already two answers, which would make no sense to anyone who didn't see the original question. So, to summarize it: I couldn't work out why functions I had added to someone else's published code that I was adapting couldn't be accessed by my function calls. I didn't realise that the code I was inserting them into was "wrapped" inside an anonymous IFFE function. When I moved them below the end of the "wrapper", I was able to call them from outside the IFFE.)
Thanks javinor, for the link to that very informative article explaining the IFFE function.
As for the method shown below, I have since found a better way to do it. I learned that div elements do not really belong in the HTML head section, so this is a better way:
var lnk;
lnk = document.createElement('LINK');
lnk.rel = 'stylesheet';
lnk.type = 'text/css';
lnk.href = 'CanvasStylesA.css';
document.getElementsByTagName('head')[0].appendChild(lnk);
You can wrap a condition around the href line that decides which file to use.
HTML
<head>
<div id="conditionalCSSincludes">
<!--
The javascript below will insert an inner div section here called "CanvasStyles", which
will, conditionally, contain one of the following two lines. That line will link to one of
two external style sheets containing the canvas style for the canvas displayed by this page.
<link rel="stylesheet" type="text/css" href="CanvasStylesA.css">
<link rel="stylesheet" type="text/css" href="CanvasStylesB.css">
The two style sheets differ with respect to the background image set for Canvas1.
A sets it to A.jpg, B sets it to B.jpg.
-->
</div>
<script src="code.js" type="text/javascript"></script>
<!-- the javascript below goes here -->
</head>
<body>
<canvas width="530" height="530" id="Canvas1">
<p>This page will not display correctly because your browser does not support the canvas element. Sorry.</p>
</canvas>
</body>
Javascript
<script type="text/javascript">
var includesDiv1, includesDiv2, includesDiv3, dt, hour, Bgnd;
// Conditional code that, depending on page load time, chooses
// whether to display the night-time or daytime background
dt = new Date();
hour = dt.getHours();
// for testing, enable the line below and set the hour manually ...
// hour = 6;
if (hour < 6 || hour >= 18){Bgnd = 1;} else{Bgnd = 2;}
// These are the two versions of the include link to the external style sheets:
includesDiv1 = '<div id="CanvasStyles"> <link rel="stylesheet" type="text/css" href="CanvasStylesA.css"> </div>';
includesDiv2 = '<div id="CanvasStyles"> <link rel="stylesheet" type="text/css" href="CanvasStylesB.css"> </div>';
if (Bgnd==1){
includesDiv3 = includesDiv1; // use the night-time background image
}
else{
includesDiv3 = includesDiv2; // use the daytime background image
}
// Insert into the conditionalCSSincludes div above an inner div called "canvasStyles".
// It contains an html include link to an external css file containg canvas styles.
cssIncludesDiv = document.getElementById("conditionalCSSincludes");
cssIncludesDiv.innerHTML = includesDiv3;

just below
window.startClock = startClock;
window.stopClock = stopClock;
add
window.yourFunctionName = yourFunctionName
do that for your three functions, so they will be available in the global (window) scope

#pawel hit the button, everything defined within the IIFE (function () {}()) cannot be accessed outside of the IIFE scope.
Take a look at this very enlightening explanation about modules and namespaces.

Related

How to print 1-3 images onto a single output page?

I have a code block in Squarespace that results in showing a photograph. The photo is currently set at 2500px wide. My goal is to have a print button that allows the user to print this image - but the most important thing is that I want it to print onto a single page. Most likely my final code will require printing three images - again, onto a single page. I'm not a programmer at all and have relied on tracking down the following code to works to isolate the image(s) and print them. However, right now the images print onto 4-8 pages! I need to find javascript or CSS code to make sure that the final print is restricted to a single page. Can anyone modify my current code to do that?
I realize this question is similar to many other posted questions. However, I've tried #media print CSS commands, but they don't seem to work at all (likely due to me not understanding the code!).
<!DOCTYPE html>
<html>
<head>
<title>Printdiv</title>
</head>
<body>
<script type="text/javascript">
function printyourimage(){
var print_div = document.getElementById("image1");
var print_area = window.open();
print_area.document.write(print_div.innerHTML);
print_area.document.close();
print_area.focus();
print_area.print();
print_area.close();
}
</script>
<form>
<input type="button" value="Print Image" onclick="printyourimage()">
</form>
</body>
</html>
To recap: this function prints a single image onto multiple pages; however, I want to restrict the final print job to a single piece of paper. If I change the code to accommodate two or three images, I still want this to code to direct the images to print onto a single piece of paper.
This is untested, but in theory it should work. Determine the number of images being displayed image_count, then using a switch, determine the max height that the image should be displayed at in % (you might need to play with the sizes to accomplish the correct fit).
based on comments:
<style>
img{max-width:200px;margin:10px;display:block;}
</style>
original answer:
var image_count = 3;
var image_height = "85%";
switch(image_count){
case 2: image_height = "45%";
case 3: image_height = "30%";
}
var print_div = document.getElementById("image1");
var print_area = window.open();
print_area.document.write(`<html><head><style>img{max-height:${image_height};}</style></head><body>${print_div.innerHTML}</body></html>`);
print_area.document.close();
print_area.focus();
print_area.print();
print_area.close();

Losing a node reference? (javascript)

So I have this JS code :
var pElt = document.createElement("p");
var aElt = document.createElement("a");
aElt.textContent = "Text";
aElt.href = "#";
pElt.appendChild(aElt);
aElt.style.color = "red";
pElt.innerHTML += "<span> and more text</span>";
//aElt.style.color = "red";
document.getElementById("content").appendChild(pElt);
console.log(aElt); // always show the red attribute
There's probably some answer around here, but I cannot even describe the problem ; so I went with "losing node reference", even though it's not what happens here. (edit: in fact, that's what happens here, silly :))
So... Please try the code as it is. It works, the link is red, everyone is happy. Now comment the "aElt.style.color = "red";" line, then uncomment the other one, two lines below.
...
It does not work, the link still appear in black. What I thought is that the pointer linked to my node was either not valid anymore or the aElt was moved to a different memory address. But when I type "console.log(aElt)", it outputs the node correctly (well... I think it does), so I don't get why I can't access it after the .innerHTML change.
What interests me is what happens under the hood :)
Thanks!
index.html :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Question!</title>
</head>
<body>
<div id="content"></div>
<script src="script.js"></script>
</body>
</html>
When you overwrite the content of the <p> element by setting it's innerHTML, you're effectively turning the <a> back into HTML text, appending the <span> (as text), and then recreating new DOM nodes in the <p>. Your old reference still refers to the original <a> you created.
You could instead create that <span> the same way you created the <a>, and append that node to the <p> instead of overwriting .innerHTML.

inject CSS link into head prior to existing CSS link

I would like to inject some CSS into the head using link tags. I can get this to work pretty easily using
var linkNode = document.createElement('link');
linkNode.href = '"+ jqueryTablesorterCSS_URL +"';
linkNode.type = 'text/css';
linkNode.rel = 'stylesheet';
documentHead.appendChild(linkNode);
However I would like to have another already existing link tag be the last item in the head as it needs to take precedence. I do not have control over this other link tag and it already exists on the page.
Moving the other element by finding it like this does not seem to work.
var documentHead = document.head;
var customCSSNode = documentHead.querySelector("link[href$='custom.css']");
documentHead.appendChild(customCSSNode);
I feel kind of gross for suggesting this as it seems "wrong", though also seems to work when I tested it. I think if you wait for the load event on the new css you can reload the existing by adding it back to the the "head" with appendChild
Note in this sandbox "head" is actually "body".
You can manually play with the ordering of the two css files, but I believe the effect you want is correctly applied when this result shows a split background with a rose in the center/right.
If the rose is on the left or if the background is not a rose then I have failed.
You may need to open the demo in full screen. Sorry these were two easily grabbed CSS files to try to replicate what you are after.
var documentHead = document.body;
var existingNode = document.getElementById("existing");
var linkNode = document.createElement('link');
linkNode.type = "text/css";
linkNode.rel = "stylesheet";
linkNode.onload = function(){ documentHead.appendChild(existingNode); }
linkNode.href = "http://www.csszengarden.com/220/220.css";
documentHead.appendChild(linkNode);
<link id="existing" rel="stylesheet" type="text/css" href="http://www.csszengarden.com/120/120.css" />
<div>Success if background pink rose in center</div>
<div>Fail if background pink rose on left</div>
<div>fail if kind of blue hand print</div>

Changing paragraph style using childNodes in JavaScript

I'm new at JavaScript. I have an html document and I want to change to fontsize of paragraphs that are inside a div but I'm having a problem. I got this error in the console:
Uncaught TypeError: Cannot set property 'fontSize' of undefined codigo.js:5
This is my html:
<!DOCTYPE html>
<html leng="es">
<head>
<meta charset="UTF-8">
<title>Mi ejercicio DHTML</title>
<link rel="stylesheet" type="text/css" href="css/estilos.css">
<script type="text/javascript" src="js/codigo.js" ></script>
</head>
<body>
<div id="parrafos">
<p>
Your bones don't break, mine do. That's clear. Your cells react to bacteria
</p>
<p>
Your bones don't break, mine do. That's clear. Your cells react to bacteria
</p>
<p>
Your bones don't break, mine do. That's clear. Your cells react to bacteria
</p>
<p>
Your bones don't break, mine do. That's clear. Your cells react to bacteria
</p>
<p>
Your bones don't break, mine do. That's clear. Your cells react to bacteria
</p>
</div>
</body>
</html>
This is my js:
window.addEventListener('load', inicio);
function inicio(){
var parrafos = document.getElementById('parrafos');
parrafos.childNodes[0].style.fontSize='10px';
}
What I want is by using the childNodes on the div called parrafos change the style of every paragraph by accessing its index parrafos.childNodes[2].style.... etc etc
[EDIT]
I ended with this code:
window.addEventListener('load', inicio);
function inicio(){
var parrafos = document.getElementById('parrafos');
parrafos.childNodes[1].style.fontSize='1.5em';
parrafos.childNodes[3].style.fontSize='1.3em';
parrafos.childNodes[5].style.fontSize='.5em';
parrafos.childNodes[7].style.fontSize='1em';
parrafos.childNodes[9].style.fontSize='.2em';
}
and I found that because of space en html documents it doesn't follows a consecutive order it seems weird because I thought it should go consecutive.
Try this:
window.addEventListener('load', inicio);
function inicio(){
var parrafos = document.getElementById('parrafos');
for (var i=0; i<parrafos.children.length; i++) {
parrafos.children[i].style.fontSize = '10px';
}
}
In your example you should set the fontSize to '10pt' instead of '10px' (or '1em') see: http://jsfiddle.net/K9Uhn
var parrafos = document.getElementById('parrafos');
parrafos.childNodes[1].style.fontSize='10pt';
Also, You should also look into using jQuery for this. It would save you a ton of headaches as it handles the element iteration and dom issues itself. For example, the jQuery code to change all the font sizes for the above example would be
$("#parrafos").css("font-size", "10pt");
No need to do the for loop yourself, jQuery handles all this. And, it's compatible with all browsers (something you will find is a huge plus): www.jquery.com
Tweaking the styles like this on a per-element basis is not a good idea. Stylesheets and element clases are your friend!
Please think about the next guy who picks up your code. They need to change the font size. They look in the stylesheet, where you would expect to find that value, and it's not there. After a few hours they find it in the JavaScript, where you wouldn't expect it. Then they get off work, drink heavily and botch about your code to their friends because of how hard you just made their day.
Maintanability is the thing that minimizes how often this scenario occurs.
So instead, how about you give your body class a tag, and have some styles that change font sizes based on that?
/* Stylesheet */
p {
font-size: 16px
}
body.small p {
font-size: 10px
}
Now your JS function that takes the action simply becomes this:
// Javascript
function inicio(){
document.body.className = 'small';
}
Which is far easier to manage.
See it work here: http://jsfiddle.net/s6BAf/
In general, dont use inline styles in your HTML, or set CSS values directly in your javascript if you can avoid it. Instead, manipulate the classes of elements on your page, and let your stylesheet do what it does: style your content.

Is there a limitation on an IFRAME containing another IFRAME with the same URL?

In order to play around a bit with frame hierarchy I wrote a small html page which allows nesting an arbitrary number of frames (code available at the end of the question).
However this doesn't work, on IE9 and Firefox 4 the inner frames are created but aren't rendered (the head and body are empty):
and on Chrome it works for two levels and then if I click the Add button on the inner frame nothing happens (no error message in the console either).
If I copy the file N times and have each file use a different file it works for any depth (but not if there's a cycle).
I tried to search for such a limitation but I must not have used the right keywords. Does anyone have any reference for this?
Here's the addRemoveFrames.html file:
<!DOCTYPE html>
<html>
<head>
<title>Add and Remove Frames</title>
<script type="text/javascript">
function add() {
var f = document.createElement('iframe');
f.src = 'addRemoveFrames.html';
document.getElementById('frameContainer').appendChild(f);
}
function remove() {
var c = document.getElementById('frameContainer');
var f = c.lastChild;
if (f)
c.removeChild(f);
}
</script>
</head>
<body>
<input type="button" onclick="add()" value="Add"/>
<input type="button" onclick="remove()" value="Remove"/>
<hr />
<div id="frameContainer"></div>
</body>
</html>
I've modified #davin's answer slightly so each frame's URL reflects its full path in the hierarchy.
var counter = 0;
function add() {
var f = document.createElement('iframe');
var sep = location.search ? (location.search + '.') : "?";
f.src = 'addRemoveFrames.html' + sep + ++counter;
document.getElementById('frameContainer').appendChild(f);
}
Looks like a sensible browser security mechanism to prevent an infinite loop of nested iframes (even though in your case it wouldn't be infinite).
In any case, a simple workaround could be to add a useless query parameter to the url, making the browser think the page loaded isn't identical, but really it is.
So instead of your current function add(), something like this (I went all out so id doesn't polute the global namespace):
var add = (function(){
var id = 0;
return function(){
var f = document.createElement('iframe');
f.src = 'addRemoveFrames.html?useless=' + id++;
document.getElementById('frameContainer').appendChild(f);
};
})();
Here is an official reference: Implementing HTML Frames - W3C Working Draft 31-Mar-97. The heading is 'Infinite Recursion' and states that if the src is equal to the parent URL, it should be treated as empty.
I would recommend the technique davin uses, or use pure DOM to create nested elements instead of IFRAMEs, which would make programmatic changes easier and potentially use less memory, as well as avoiding that issue with delayed loading.
I tested it with chrome, the maximum image nesting is 4. inside the second "asd" (red one) is an iframe, but the is empty
If i include a third page, the nesting increases
Conclusion: depends in the url, if you have an unlimited amount of nested UNIQUE urls, you can nest indefinitely

Categories

Resources