JavaScript event handler click thumbnail to enlarge image - javascript
So I am very new to Web Design and am having issues getting my click event handler to work.I cant change the html or css files. My task is to set a click handler to my thumbnails to enlarge the image in the img within the <figure> element. While also setting the figcaption text in the figure to the thumbs title attribute. I need to attach to the div id = thumbnails. My script is not enlarging my thumbnails or titles.
This is my created HTML Doc:
<!DOCTYPE html>
<html lang="en">
<head >
<meta charset="utf-8">
<title>Chapter 9 - Share Your Travels</title>
<link rel="stylesheet" href="css/styles.css" />
<script type="text/javascript" src="js/chapter09-project02.js">
</script>
` `</head>
<body>
<header>
<h2>Share Your Travels</h2>
<nav><img src="images/menu.png"></nav>
</header>
<main>
<figure id="featured">
<img src="images/medium/5855774224.jpg" title="Battle" />
<figcaption>Battle</figcaption>
</figure>
<div id="thumbnails">
<img src="images/small/5855774224.jpg" title="Battle"/>
<img src="images/small/5856697109.jpg" title="Luneburg"/>
<img src="images/small/6119130918.jpg" title="Bermuda" />
<img src="images/small/8711645510.jpg" title="Athens" />
<img src="images/small/9504449928.jpg" title="Florence" />
</div>
</main>
</body>
</html>
Js script:
var thumbs = document.getElementById("thumbnails");
thumbs.addEventListener("click", function (e) {
if (e.target.nodeName.toLowerCase() == 'img') {
var clickedImageSource = e.target.src;
var newSrc = clickedImageSource.replace("small", "medium");
var featuredImage = document.querySelector("#featured img");
featuredImage.src = newSrc;
featuredImage.title = e.target.title;
}
});
var img = document.getElementById("figcaption");
img.addEventListener("mouseover",function (event) {
img.className = "featured figcaption";
});
img.addEventListener("mouseout", function (event) {
img.className = "featured figcaption";
var element = document.getElementById('figcaption');
element.style.opacity = "0.9";
element.style.filter = 'alpha(opacity=0%)';
});
Thanks for any advice and hopefully I can pay it forward for someone else!
I think it causes you the problem. The JS is getElementById, but there's no ID is call figcaption.
var img = document.getElementById("figcaption");
The problem is that you are trying to use getElementById to find something with the id of figcaption; nothing on the page has an id of figcaption, so getElementById returns null.
There are a few ways you could fix it:
Add an id to your <figcaption> element: <figcaption id="figcaption">
Instead of using getElementById, use getElementsByTagName: document.getElementsByTagName('figcaption')[0];. (getElementsByTagName always returns a collection of elements, the [0] grabs the first, and in this case only, one in the collection).
Instead of using getElementById, use querySelector like you did to find the featured image element: document.querySelector("#featured figcaption");
This last approach of using querySelector is what I would recommend in this situation; other times it might be better to add an id to the element.
const thumbs = document.getElementById("thumbnails");
const featuredImage = document.querySelector("#featured img");
const caption = document.querySelector("#featured figcaption");
thumbs.addEventListener("click", function (e) {
if (e.target.nodeName.toLowerCase() == 'img') {
var clickedImageSource = e.target.src;
// for the purposes of this demo, I'm using a placeholder
// image service so I need to change the size slightly differently
let newSrc = clickedImageSource.replace("50x50", "350x150");
//var newSrc = clickedImageSource.replace("small", "medium");
featuredImage.src = newSrc;
caption.textContent = e.target.title;
}
});
caption.addEventListener("mouseover",function (event) {
caption.className = "featured figcaption";
});
caption.addEventListener("mouseout", function (event) {
caption.className = "featured figcaption";
// I changed the value to .5 instead of .9 because with such small
// text the opacity change is barely perceivable.
caption.style.opacity = "0.5";
// This is not needed, this was the old way IE used to do it,
// IE < 9 needed it, but IE < 9 is no longer relevant. Just use opacity.
//element.style.filter = 'alpha(opacity=0%)';
});
<header>
<h2>Share Your Travels</h2>
<nav><img src="http://via.placeholder.com/50x50?text=Menu"></nav>
</header>
<main>
<figure id="featured">
<img src="http://via.placeholder.com/350x150" title="Battle">
<figcaption>Battle</figcaption>
</figure>
<div id="thumbnails">
<img src="http://via.placeholder.com/50x50" title="Battle">
<img src="http://via.placeholder.com/50x50/ff0000/ffffff" title="Luneburg">
<img src="http://via.placeholder.com/50x50/00ff00/ffffff" title="Bermuda">
<img src="http://via.placeholder.com/50x50/0000ff/ffffff" title="Athens">
<img src="http://via.placeholder.com/50x50/000000/ffffff" title="Florence">
</div>
</main>
A few things to note about my version, I used let and const instead of var. Both let and const are well supported these days and should be used instead of var unless you need to support very old browsers. I also only query for the caption and featured image elements once and store them in the scope above the click handler, this allows the code inside the click handler to have access to them via closure. This makes everything slightly more efficient since you don't have to query the DOM to find them each time the click handler runs. In this case the performance gain is moot but it is good to be in the habit of writing code as efficiently as possible so you don't have to think about it when it does matter.
Images are void elements, meaning they can't have any content, so you don't need a closing tag. For this reason I used bare <img> tags instead of self-closing <img /> tags. Self-closing images were only ever needed in XHTML, since it was XML, which has a more rigid syntax than HTML. Another thing to note, you don't need the type="text/javascript" on your <script> tags, it just takes up extra space and doesn't really do anything.
I don't understand what you are trying to do with the mouseover and mouseout handlers. Currently what your code does is:
When the mouse moves over the caption, the featured and figcaption classes are added to the caption.
When the mouse leaves the caption, the featured and figcaption classes are again added to the caption and its opacity is set to 0.9, effectively permanently.
I cleaned it up a little in my example to make it more obvious that is what is happening.
Related
Swapping images back and forth on click in multiple places
I'm creating an accordion with my own arrow icons (pngs) as the "toggle" so when you click on the down red arrow, the up blue arrow will show to collapse, and vice versa. I got it to work with the below code, but I have multiple accordions with the same arrow icons, and I need them all to do this. When I add the same code to the other accordions (even if I changed out the ID to be unique and update it in the JS), it still only wants to toggle the first accordion. Can anyone help me get this to work across multiple image sets (but the same images)? HTML: <img src="/wp-content/uploads/2019/08/accordion-open.png" alt="accordion icon" id="accordion" onclick="change();"></div> JS: var image_tracker = 'open'; function change(){ var image = document.getElementById('accordion'); if(image_tracker=='open'){ image.src='/wp-content/uploads/2019/08/accordion-close.png'; image_tracker='close'; } else{ image.src='/wp-content/uploads/2019/08/accordion-open.png'; image_tracker='open'; } }
If you're assigning the listener by ID it's only going to apply to the first one. Try using a class name instead. <html> <body> <img class="accordion_icon" src="/wp-content/uploads/2019/08/accordion-open.png" /> <script type="text/javascript"> var open_src = "/wp-content/uploads/2019/08/accordion-open.png"; var close_src = "/wp-content/uploads/2019/08/accordion-close.png"; let accordion_icons = document.getElementsByClassName('accordion_icon'); // get all icons img tags for (let i = 0; i < accordion_icons.length; i++) { const element = accordion_icons[i]; element.addEventListener('click',(event)=>{ // set listener on each one console.log('src was: ', event.currentTarget.src); event.currentTarget.src = (event.currentTarget.src == open_src ? close_src : open_src) // change the src to the one it currently isn't console.log('scr is now: ', event.currentTarget.src); }); } </script> </body> </html>
An alternative method could be also this one, if you still want to keep the even handler in the HTML: <img src="/wp-content/uploads/2019/08/accordion-open.png" alt="accordion icon" id="accordion" onclick="change(this);"></div> And in the JS: function change(image){ image.src = image.src.endsWith("open.png") ? image.src.replace(/open\.png$/, "close.png") : image.src.replace(/close\.png$/, "open.png"); }
Using html2canvas to convert to image on keyup & keypress
I am building a application where user can write something inside input and it will be converted to a image they can download. I use html2canvas.js for converting text to a downloadable image (this part works fine) Currently it take the text inside <div id="talltweets"></div> and converts it to a image, but what I want is to be able to change the text/image when writing text inside input. I tried to make a function called edValueKeyPress and it takes whats inside the input and adds it into <div id="talltweets"></div>, Now how can I take the text inside #talltweets and add it to <img id="textScreenshot"/> in realtime/when writing? This is my code: html2canvas(document.getElementById("talltweets"), { onrendered: function(canvas) { var screenshot = canvas.toDataURL("image/png"); document.getElementById("textScreenshot").setAttribute("src", screenshot); } }); function edValueKeyPress() { var edValue = document.getElementById("body"); var s = edValue.value; var lblValue = document.getElementById("talltweets"); lblValue.innerText = s; } <script src="http://files.codepedia.info/uploads/iScripts/html2canvas.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js" type="text/javascript"></script> <input type="text" onKeyPress="edValueKeyPress()" onKeyUp="edValueKeyPress()" id="body"> <div id="talltweets"></div> <!-- The PNG image will be added here--> <div> <img id="textScreenshot" /> </div>
Basically, you need to wrap that whole rendering step of the process into a function that can then be called with the keypress event. You're already on the right track - here's one way you could implement this (plus a few miscellaneous code improvements; also, I had to change the URL for html2canvas to pull from a different cdn, as the original one wasn't loading correctly from SO): // If we store these, we only need to query the dom once, not on every update var tallTweets = document.getElementById('talltweets'); var screenshotImg = document.getElementById('textScreenshot'); var textInput = document.getElementById('body'); // Note - it wouldn't surprise me if html2canvas has a specific API // for doing this kind of update. Worth checking their documentation for. function updateImage() { html2canvas(tallTweets, { onrendered: function(canvas) { var screenshot = canvas.toDataURL("image/png"); screenshotImg.setAttribute("src", screenshot); } }); }; function edValueKeyPress() { tallTweets.innerText = textInput.value || ''; updateImage(); } updateImage(); <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js" type="text/javascript"></script> <input type="text" onKeyPress="edValueKeyPress()" onKeyUp="edValueKeyPress()" id="body" placeholder="Type something!"> <div id="talltweets"></div> <!-- The PNG image will be added here--> <div> <img id="textScreenshot" alt="Generated screenshot" /> </div> You could also make it even simpler by combining the two functions into one - IE, moving tallTweets.innerText = textInput.value into updateImage, and then binding the event listener to updateImage instead. But keeping them separated has its advantages, especially if you might want to reuse updateImage elsewhere.
How to change an img src with javascript?
I know there are other questions like this and I've tried following them I'm just not aware of what exactly I'm doing wrong. I've declared the pic variable as being linked to the image with the corresponding id of 'pic' and I've tried many different examples and trying to follow other questions like this but to no avail. --- THE REAL QUESTION ---- I would like the image to change its src to another one that I have in my workspace with the click of a button. HTML: <img class="trans" id="pic" src="images/link_rouge.png" alt="" width="1000" height="333" /> JavaScript: var pic = document.getElementById('pic'); function rouge() { pic.src = "images/link_rouge.png"; } function blue() { pic.src = "images/link_blue.png"; } I know the functions already work with the buttons because they are affecting some divs on the page that change color the only things not changing are the images.
The EventTarget.addEventListener() method registers the specified listener on the EventTarget it's called on. Use addEventListener over button elements to attach click events and bind your handler functions to those events. var pic = document.getElementById('pic'); function rouge() { pic.src = "http://www.projectvictorycosplay.com/images/zelda/Links/3198_render_link.png"; } function blue() { pic.src = "http://bin.smwcentral.net/u/1944/Link%2BBlue%2BTP%2Bshrunk.png"; } document.getElementById('btn1').addEventListener('click', rouge); document.getElementById('btn2').addEventListener('click', blue); img { width: 200px; } <button id='btn1'>rouge</button> <button id='btn2'>blue</button> <br/> <img class="trans" id="pic" src="http://www.projectvictorycosplay.com/images/zelda/Links/3198_render_link.png" alt="" width="1000" height="333" />
There's a chance your page has not loaded before pic is set equal to document.getElementById('pic');. You can use something like jQuery's $(document).ready() function (or document.addEventListener("DOMContentLoaded", handler);) to ensure your page is fully loaded before assigning the pic variable. $( document ).ready(function() { var pic = document.getElementById('pic'); function rouge() { pic.src = "images/link_rouge.png"; } function blue() { pic.src = "images/link_blue.png"; } }); Note: You will need to pull the JQuery library into your project to use this method. See here. Also, you can read this post to learn a little more about HTML/JavaScript and page loading.
jQuery hover on imagemap does not work
I have an imagemap and want to add a jQuery hover. Basically the whole image shall be replaced with a new one, based on an imagemap. Hovering on certain parts of the image shall result in replacing the image completely. On a mouseout of the mapped areas, it shall flip back to the imagemap. It works fine doing the imageflip with javascript, but I want to change it to jQuery in order to have mor control about the fadeIn and stuff like this. It just seems easier in jQuery. Here is what Ive got. <html> <head> <!-- LINK ZU JQUERY ONLINE--> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <script> //PRELOAD THE IMAGES original = new Image(698, 360); original.src = "imagenes_png/bosque_mapa.png"; azul = new Image(698, 360) azul.src = "imagenes_png/azul_mouse.png"; verde = new Image(698, 360) verde.src = "imagenes_png/verde_mouse.png"; //jQUERY HOVER $(document).ready(function(){ $("#verdeA").hover(function() { $(this).attr("src" , "verde.src"); }, function() { $(this).attr("src" , "original.src"); $("#azulA").hover(function() { $(this).attr("src" , "azul.src"); }, function() { $(this).attr("src" , "original.src"); }); }); }); </script> <body> <!-- INSERT THE PICTURE --> <img name="bosque" id="bosque" src="imagenes_png/bosque_mapa.png" width="698" height="360" border="0" usemap="#bosque_m" alt="Bosque con animales" /> <map name="bosque_m" id="bosque_m"> <area id="verdeA" shape="poly" coords="643,324,646,322,648,321,651,320,654,320,656,321,658,323,659,324,660,327,659,330,657,332,655,334,654,335,654,332,653,329,653,327,650,326,648,328,648,331,649,332,650,334,652,335,654,337,656,338,658,339,660,341,662,342,662,345,661,348,660,350,657,351,656,351,656,346,656,345,653,347,651,350,650,351,651,353,651,354,653,356,656,356,658,356,660,356,662,356,666,354,668,351,669,349,670,347,669,346,665,346,666,342,667,341,668,340,670,339,672,339,674,341,676,344,676,347,675,351,672,355,670,357,669,360,642,360,644,356,646,353,647,350,648,346,650,340,650,337,646,332,645,330,644,327,643,324" alt="" /> <area id="azulA" shape="poly" coords="472,249,476,249,479,250,483,251,484,255,485,258,487,261,489,263,493,265,498,266,501,268,504,270,504,271,499,270,495,269,489,268,486,269,484,270,480,269,476,268,473,266,470,262,469,260,468,256,470,253,472,249" alt="" /> </map> </body> </html> First I preload the images that the imageflip works without delay. Then I delcare the jQuery function, based on the id in my imagemap and then I add the names of the pictures assigned in the preloading. Buut, it does not work, at all. Nothing is happening. Where is the mistake?
There are two problems: First, when you refer to $(this) in your hover handlers, $(this) is referring to your <area> elements, not your <img>. You'll want to refer instead to $("#bosque"). Second, you are setting the src attribute to the actual strings verde.src, azul.src and original.src. It's as if you were saying <img src="verde.src">, which is not what you want. Remove the quotes from around those strings, as in: $("#bosque").attr("src", verde.src"); so that you are setting src equal to the src property of the verde object and not just to a relative URL that is broken. So the hover section becomes this: $(document).ready(function(){ $("#verdeA").hover(function() { $("#bosque").attr("src" , verde.src); }, function() { $("#bosque").attr("src" , original.src); $("#azulA").hover(function() { $("#bosque").attr("src" , azul.src); }, function() { $("#bosque").attr("src" , original.src); }); }); }); Which only reacts to the mapped areas:
Javascript. Can't get element style
I'm trying to get width & height of the img element. It gives 0px whatever I do. function foo(element){ if(element){ var el=document.querySelector(element); var img=el.getElementsByTagName("img")[0]; alert(img.style.width); } } foo(); And the html: <div id="theid" class="theclass"> <img id="img" alt="img" name="the img" src="img/img.jpg" /> </div> <script> foo("#theid"); </script> I've also tried .offsetWidth, .clientWidth and defaultView.getComputedStyle(img,"");
How about this function foo(imgId){ var img=document.getElementById(imgId); alert(img.offsetWidth); } foo('img');
Use .naturalWidth & .naturalHeight to get the actual size of image function foo(element){ if(element){ var el=document.querySelector(element); var img=el.getElementsByTagName("img")[0]; alert(img.naturalWidth ); } } foo("#theid"); DEMO
Image height/width is always returned 0px unless defined in CSS. Try this piece of code, but you are loading the image again in this case (could be cached, but still). var image = new Image(); // replace with appropriate library method image.addEventListener("load", function() { //get image height/width here }, false); image.src = el.getElementsByTagName("img")[0].src;
You need to use the element offsetWidth Here is a working fiddle and the code: function foo(element) { if (element) { var el = document.getElementById(element); alert(el.offsetWidth); } } foo("theid"); Note that I have used the document.getElementById only as that will get the element. No need to have getElementsByTagName in this case. And do not prefix the id with a '#' as that notation is of jquery not javascript.
<div id="theid" class="theclass"> <img id="img" alt="img" name="the img" src="img/img.jpg" /> </div> <script> foo("#theimg"); </script> You are calling foo() by passing #theimg which is not present in document, call by passing #img , i.e. like this <script> foo("#img"); </script> if you use above img id, remove var img=el.getElementsByTagName("img")[0]; in your function, we can directly access it.Okay <script> foo("#theid"); </script> use this to keep your function as it is. Okay It'll give 0px, if the image failed to load otherwise it'll give the width and height of the actual image, And if you want to access the attributes like left, right, top, bottom for these attributes we need to set image position to absolute then we can access.