How to reduce this jquery toggle code for an image map - javascript

I am trying to figure out how to reduce this code down! it basically hides an image then show a div depending on what image map area is clicked!
I have a code pen of a working demo here: http://codepen.io/naniio/pen/wBExYq
$(document).ready(function() {
$(".auckland").click(function() {
$(".map").toggle();
$("#aukl.hide").toggle();
});
$(".gisborne").click(function() {
$(".map").toggle();
$("#gisb.hide").toggle();
});
$(".wellington").click(function() {
$(".map").toggle();
$("#well.hide").toggle();
});
$(".nelson").click(function() {
$(".map").toggle();
$("#nel.hide").toggle();
});
$(".christchurch").click(function() {
$(".map").toggle();
$("#chch.hide").toggle();
});
$(".queenstown").click(function() {
$(".map").toggle();
$("#queen.hide").toggle();
});
$(".otago").click(function() {
$(".map").toggle();
$("#ota.hide").toggle();
});
});
I have tried using find and other jquery methods but I must be looking in the wrong places
Any help would be great I'm new to jQuery but not new to stack overflow I can imagine this is an easy question/fix for some and this may be rated harshly or ignored! but for those who continually help this community regardless, thanks! :)

I have something working in this pen. http://codepen.io/anon/pen/ByOEam
Just add an extra attribute in the area tags
$(document).ready(function() {
$(".clickable").click(function() {
var toHide = $(this).attr('data-hide');
$(".map").toggle();
$("#"+toHide).toggle();
});
$(".hide").click(function() {
$(".map").toggle();
$(this).toggle();
});
});

A little refactoring to <area> tags like this
<area shape="circle" coords="220,97,15" alt="Auckland" title="Auckland" href="#" data-ref="aukl.hide">
would cleanup your html from unnecessary classes and would give you cleaner javascript code:
$(document).ready(function() {
$("map area").click(function() {
$(".map").toggle();
$("#" + this.data("ref")).toggle();
});
});

Add class to the all the div that will be clicked, say "lands", and use following code,
$(".lands").click(function() {
var $this = $(this);
$(".map").toggle();
$this.toggle();
});

Try this reduced jquery code
$(document).ready(function() {
$('.box').on('click',function(){
$(".map").toggle();
$(this).toggle();
});
});

Every time you need to add the same behavior to many different objects probably a good pattern is to use a function and dynamic creation.
For example in your specific case I'd expect to have
An image with the map (without dots)
A list of locations (possibly retrieved from a DB)
Code that for each of the locations creates the dot image correctly positioned on the map
Something like:
function addLocation(x, y, name, data) {
var dot = document.createElement("img");
dot.className = "dot";
dot.onload = function() {
// x,y coordinates are relative to map size to account
// for responsive designs
dot.left = (x*mapContainer.offsetWidth - dot.offsetWidth/2) + "px";
dot.top = (y*mapContainer.offsetHeight - dot.offsetHeight/2) + "px";
mapContainer.appendChild(dot);
};
dot.src = "dot.png";
dot.onclick = function() {
showMap(name, data);
};
}
This way adding/changing a location only requires updating the database (or the static data array if using a database is not worth at the moment).
Adding by hand location names and chart names (that are random small variations one of the other like gisborne->gisb but christchurch->chch) is a step toward making the page a maintenance nightmare.

Related

Cycle through classes on Jquery to animate

enter image description here
I'm trying to create an animation where if you click the button the circles animate around the path and changes size. I'm not sure how i would cycle the classes on the next click ?
http://bluemoontesting.co.uk/bluemoon2016/people.html
I'm using an svg and have targeted the elements with this so far:
<script>
$(".animate-slider").click(function() {
$('.st7').toggleClass("top-left");
$('#XMLID_292_').toggleClass("left");
$('#XMLID_293_').toggleClass("center-right");
$('#XMLID_297_').toggleClass("top-right");
$('#XMLID_301_').toggleClass("top");
$('#XMLID_283_').toggleClass("top-center");
});
</script>
If anyone could help me i'd be very grateful :)
Thanks
I would take a little different approach. Instead of toggling classes, to get it to move to more than two positions, you will need to cycle the classes assigned to each element instead. Storing the class names in an array would allow you to move them in the array to cycle the position that each element moves to next. I created a simplified example.
$(document).ready(function () {
var steps = ['right', 'bottom-right', 'bottom-left', 'left', 'top'],
allClasses = steps.join(' ');
$('#go').click(function() {
$('#a').removeClass(allClasses).addClass(steps[0]);
$('#b').removeClass(allClasses).addClass(steps[1]);
$('#c').removeClass(allClasses).addClass(steps[2]);
$('#d').removeClass(allClasses).addClass(steps[3]);
$('#e').removeClass(allClasses).addClass(steps[4]);
steps.push(steps.shift()); // move first element to the end
// to cycle in the other direction you would pop and unshift instead
// steps.unshift(steps.pop()); // move last element to the beginning
});
});
You could just use setInterval like so:
var $st7 = $('.st7'); //class selectors can be expensive, so cache them
function rotate() {
$st7.toggleClass("top-left");
$('#XMLID_292_').toggleClass("left");
$('#XMLID_293_').toggleClass("center-right");
$('#XMLID_297_').toggleClass("top-right");
$('#XMLID_301_').toggleClass("top");
$('#XMLID_283_').toggleClass("top-center");
}
//2000 is milliseconds, so that's two seconds
var rotateIntervalId = setInterval(rotate, 2000);
//optionally consider stopping/starting the effect on mouse hover/exit
$('#Layer_1').on('hover', function() {
clearInterval(rotateIntervalId);
}).on('blur', function() {
rotateIntervalId = setInterval(rotate, 2000);
});

Find all links which _only_ contain an image

to add a click-to-zoom feature to images, I used the following code to toggle a class:
$(document).ready(function() {
var imageLinks = $('a[href$=".png"], a[href$=".jpg"], a[href$=".gif"], a[href$=".bmp"]');
if (imageLinks.children('img').length) {
imageLinks.children('img').each(function() {
$(this).attr('title', '(click to enlarge image)');
});
imageLinks.click(function(e) {
e.preventDefault();
$(this).children('img').toggleClass('expanded');
});
}
});
Now my problem is, I could have text links, like <a href='file.png'>text</a> as well on that page, and they are broken by this code.
Is there a way to select only image links (<a href='file.png'><img src='file.png'></img></a>) instead of all links to image files?
Thanks in advance!
You could use has statement:
var imageLinks = $('a').filter(':has(img)');
Or the same:
var imageLinks = $('a:has(img)');
I believe this will work:
var $images = $('a > img');
$images.attr('title', '(click to enlarge image)');
$images.parent().click(function(e) {
e.preventDefault();
$(this).children('img').toggleClass('expanded');
});
Example jsFiddle: http://jsfiddle.net/UHkh7/
You can change the selector to 'a img' if the img is not always a direct descendent of the a tag, however you will then need to change $images.parent() to $images.parents('a')[0]

Simple automated image changer malfunction

I have a simple image changer that swaps between 2 images by a very simple bit of jQuery but for reasons unknown, probably lack of sleep, I cannot get it to work as wanted.
Take a look at this jsfiddle to see what's going on.
Here's the js;
$(document).ready(function () {
function swap() {
$('#display').attr('id', 'hidden').hide();
$('#hidden').attr('id', 'display').fadeIn(500);
}
setInterval(swap, 2000);
});
Thanks!
fadeToggle is indeed the best solution, but another solution could be something like this.
If you want to add some extra logic to the toggle next to your hide and fadein.
function swap() {
if($("#display").is(":visible"))
{
$('#display').hide();
$('#hidden').fadeIn(500);
}
else
{
$('#display').fadeIn(500);
$('#hidden').hide();
}
}
http://jsfiddle.net/Rws8c/2/
Is this about what you're looking to do:
$(document).ready(function () {
function swap() {
$('#display').fadeToggle(500);
$('#hidden').fadeToggle(500);
}
setInterval(swap, 2000);
});
The following uses a slightly different approach that enables you to easily add more than 2 images:
HTML
<!-- Define a single img element -->
<img src="http://musicglue-profile-pages.s3.amazonaws.com/wp-content/uploads/2013/03/NiceandSlezzy.png" alt="The Tin Pigeons" title="The Tin Pigeons" id="display">
JavaScript / jQuery
$(document).ready(function () {
// create an array that contains a entry for each img src. For more images, just add additional array entries.
var images = ['http://musicglue-profile-pages.s3.amazonaws.com/wp-content/uploads/2013/03/NiceandSlezzy.png',
'http://musicglue-profile-pages.s3.amazonaws.com/wp-content/uploads/2013/03/La-Route-Du-Rock1.jpg'];
var curImage=images.length-1;
var $image = $('#display');
function swap() {
$image.hide().attr('src', images[curImage]);
if (curImage==images.length-1) {
curImage=-1
}
curImage++;
$image.fadeIn(500)
}
setInterval(swap, 2000);
});

Appending hash/subpage to URL when loading content in expanding divs

I'm loading in separate .html documents inside divs with this code:
JS
$('.thumbnail').click(function() {
var idStr = ("project/"+$(this).attr('id')) + " #projectcontainer";
$('#projectcontainer').animate({opacity:0});
$('#projectcontainer').hide().load(idStr,function(){
$(this).slideDown(500).animate({opacity:1}, function() {
$.scrollTo('#gohere',800);
$('#close').fadeIn(500).css({'display': 'block', 'height': '25px'});
});
});
});
HTML
<div class="thumbnail" id="atmotype.html">
<img src="image.whatever">
</div>
It all works as intended but I also wanna append an ID when you open a project, and also be able to link directly to said content (already expanded in the div). I've been trying around and can't come up with a solution, and that being said I'm pretty awful with JS in general.
Would really appreciate if someone could enlighten me on how this works.
Right now when you click your .thumbnail element, it is firing your click() event and using $(this).attr('id') for the hash/scroll. To make this run when the page load, you should probably break it out to a separate function that takes the ID as a parameter, and then call this function from your click() event as well as a generic page load using a parameter in location.hash.
$(document).ready(function(){
if (location.hash.length>0){
/* this assumes the page to load is the only thing in the
hash, for example /page.php#project.html */
var hash = location.hash.substring(1); // get hash and remove #
addHashAndScroll(hash); // call function with page name
}
$('.thumbnail').click(function() {
addHashAndScroll($(this).attr('id')); // pass ID value to function
});
}
// this function contains most of your original script
function addHashAndScroll(id){
var idStr = "project/"+ id + "#projectcontainer";
// rest of your code
}
UPDATE:
This is the thing about js it all makes sense when explained but executing it is a bitch. Anyways thanks alot for helping out. Based on your explanation what I get is:
$(document).ready(function() {
if (location.hash.length > 0) {
/* this assumes the page to load is the only thing in the
hash, for example /page.php#project.html */
var hash = location.hash.substring(1); // get hash and remove #
addHashAndScroll(hash); // call function with page name
}
$('.thumbnail').click(function() {
addHashAndScroll($(this).attr('id')); // pass ID value to function
});
}
// this function contains most of your original script
function addHashAndScroll(id) {
var idStr = "project/" + id + "#projectcontainer";
$('#projectcontainer').animate({
opacity: 0
});
$('#projectcontainer').hide().load(idStr, function() {
$(this).slideDown(500).animate({
opacity: 1
}, function() {
$.scrollTo('#gohere', 800);
$('#close').fadeIn(500).css({
'display': 'block',
'height': '25px'
});
});
});
}
I've tried to fiddle around with the closures and whatever minimal experience i have in bug testing js but i keep getting errors originating from this line:
function addHashAndScroll(id) {

Is it possible to change the action of Bootstrap popovers based on screen width?

I asked this question regarding changing the position of a bootstrap popover depending on the size of the screen.
The answer was great - however I also now want to change the action for popovers (so it's on click for mobile) as well as the location, and am having difficulty re-factoring the code. This is what I have:
$(document).ready(function(){
$('#my_list li').popover({
placement: wheretoplace
});
});
function wheretoplace(){
var width = window.innerWidth;
if (width<500) return 'below';
return 'left';
}
How would I amend the wheretoplace function to return two things: the placement value along with a trigger value? I've got the existing stuff in a jsFiddle.
Edit - I've amended my jsFiddle above to show the complete solution, adding a click event to #James' answer below.
If you are trying to return two values from the function, try assigning them as properties of an object and then return that object.
eg.
function wheretoplace(){
var data = {};
var width = window.innerWidth;
if (width<500)
{
data.placement = 'below';
}
else
{
data.placement = 'left';
}
data.trigger = "myEvent";
return data;
}
Then in the function calling wheretoplace:
$(document).ready(function(){
$('#my_list li').popover({
placement: wheretoplace().placement,
trigger: wheretoplace().trigger
});
});
Is this what you are trying to do?
EDIT: In Response to the comment below:
As with the jsFiddle demo
By assigning the trigger as "manual" on document ready, you are then able to call $(element).popover("toggle") in a click handler which will toggle the appearance of the popover.

Categories