11

I have a body system feature I'd like to implement. When the user hovers over a body part, it highlights and shows information on that specific body part. I've coded the CSS the way I want it, but I don't know anything about JavaScript to get the information to stick when the body part is clicked or the mouse leaves the hover state.

I've searched the forum and found similar issues and have spent hours trying to figure this out myself from others' javascript solutions - I'm at the point where I need to ask for help.

Here is a flash prototype I made of my desired effect:

http://inwavemedia.com/temp/proto/Main.html

Here is the live HTML if you want to take a look at what I have now:

http://inwavemedia.com/temp/excretory.html

Here is my code:

<style type="text/css">
#bodysystem-excretory {
 width: 618px;
 height: 504px;
 background: url(excretory.png) no-repeat;
 margin: 10px auto; padding: 0;
 position: relative;
 border: 1px solid #999;
}
#bodysystem-excretory li {
    margin: 0;
    padding: 0;
    list-style: none;
    display: block;
    position: absolute;
}

#bodysystem-excretory a {
    display: block;
/*  text-indent: -9999px;*/
    text-decoration: none;
}

#esoph {
    left: 85px;
    top: 41px;
    width: 46px;
    height: 94px;
    z-index: 10;
}

#lungs {
    left: 76px;
    top: 84px;
    width: 84px;
    height: 68px;
    z-index: 20;
}

#bladder {
    left: 87px;
    top: 148px;
    width: 64px;
    height: 104px;
    z-index: 30;
}

#esoph a {
    height: 94px;
}

#lungs a {
    height: 67px;
}

#bladder a {
    height: 104px;
}


#esoph a:hover {
    background-image: url(excretory.png);
    background-repeat: no-repeat;
    background-position: -25px -561px;
}

#lungs a:hover {
    background-image: url(excretory.png);
    background-repeat: no-repeat;
    background-position: -105px -523px;
}

#bladder a:hover {
    background-image: url(excretory.png);
    background-repeat: no-repeat;
    background-position: -114px -618px;
}

.info span{ 
    display: none

}

.info{
    position:relative;
    z-index:1124;
    color:#000;
}

.info:hover{
    z-index:1125;

}

.info:hover span{
    display:block;
    position:absolute;
    top:-30px;
    left:155px;
    width:370px;
    color:#000;
    background-color:#FFFFFF;
}
</style>

</head>

<body>
<ul id="bodysystem-excretory">
  <li id="esoph">
    <a href="#" class="info"><span id="esoph-info"><h3>Esophagus</h3><p>This is esophagus information. This is esophagus information. This is esophagus information. This is esophagus information. This is esophagus information. This is esophagus information. This is esophagus information. </p></span></a>
  </li>
<li id="lungs"><a href="#" class="info"><span id="lungs-info"><h3>Lungs</h3></span></a></li>
<li id="bladder"><a href="#" class="info"><span id="bladder-info"><h3>Bladder</h3></span></a></li>
</ul>
Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
Steve
  • 121
  • 2
  • 4
  • What is your question? You've done it in css. Do you want to do it in javascript? – polin Dec 01 '12 at 07:59
  • From what I understand @polin, Steve would like to have this hover styling become permanent upon clicking. See his link, hover works fine, just like this CSS, but _clicking_ makes the styling permanent, _unlike_ this CSS. – agryson Dec 01 '12 at 09:02

5 Answers5

1

Below is the required changes you would require to do:

<head>
    <title>Untitled Page</title>
    <style type="text/css">
        #bodysystem-excretory
        {
            width: 618px;
            height: 504px;
            background: url(excretory.png) no-repeat;
            margin: 10px auto;
            padding: 0;
            position: relative;
            border: 1px solid #999;
        }
        #bodysystem-excretory li
        {
            margin: 0;
            padding: 0;
            list-style: none;
            display: block;
            position: absolute;
        }

        #bodysystem-excretory a
        {
            display: block; /*  text-indent: -9999px;*/
            text-decoration: none;
        }

        #esoph
        {
            left: 85px;
            top: 41px;
            width: 46px;
            height: 94px;
            z-index: 10;
        }

        #lungs
        {
            left: 76px;
            top: 84px;
            width: 84px;
            height: 68px;
            z-index: 20;
        }

        #bladder
        {
            left: 87px;
            top: 148px;
            width: 64px;
            height: 104px;
            z-index: 30;
        }

        #esoph a
        {
            height: 94px;
        }

        #lungs a
        {
            height: 67px;
        }

        #bladder a
        {
            height: 104px;
        }


        #esoph a:hover
        {
            background-image: url(excretory.png);
            background-repeat: no-repeat;
            background-position: -25px -561px;
        }

        #lungs a:hover
        {
            background-image: url(excretory.png);
            background-repeat: no-repeat;
            background-position: -105px -523px;
        }

        #bladder a:hover
        {
            background-image: url(excretory.png);
            background-repeat: no-repeat;
            background-position: -114px -618px;
        }

        .info span
        {
            display: none;
        }

        .info
        {
            position: relative;
            z-index: 1000;
            color: #000;
        }

        #bodysystem-excretory li[selected='true'] .info
        {
            z-index:1200;
        }

        #bodysystem-excretory li[selected='true'] .info span
        {
            display: block;
            position: absolute;
            top: -30px;
            left: 155px;
            width: 370px;
            color: #000;
            background-color: #FFFFFF;
        }

        .info:hover
        {
            z-index: 1125;
        }

        .info:hover span
        {
            display: block;
            position: absolute;
            top: -30px;
            left: 155px;
            width: 370px;
            color: #000;
            background-color: #FFFFFF;
        }
    </style>
    <script type="text/javascript">
        function SelectOrgan(obj)
        {
            var parentObj = obj.parentNode;
            var organs = document.getElementById("bodysystem-excretory").getElementsByTagName("li");

            for (var i = 0, len = organs.length; i < len; i++)
            {
                organs[i].setAttribute("selected", "false");
            }

            parentObj.setAttribute("selected", "true");
        }
    </script>
</head>
<body>
    <ul id="bodysystem-excretory">
        <li id="esoph" selected="false"><a href="#" class="info" onclick="SelectOrgan(this)"><span id="esoph-info">
            <h3>
                Esophagus</h3>
            <p>
                This is esophagus information. This is esophagus information. This is esophagus
                information. This is esophagus information. This is esophagus information. This
                is esophagus information. This is esophagus information.
            </p>
        </span></a></li>
        <li id="lungs" selected="false"><a href="#" class="info" onclick="SelectOrgan(this)"><span id="lungs-info">
            <h3>
                Lungs</h3>
        </span></a></li>
        <li id="bladder" selected="false"><a href="#" class="info" onclick="SelectOrgan(this)"><span id="bladder-info">
            <h3>
                Bladder</h3>
        </span></a></li>
    </ul>
</body>
</html>

Note that each of the organs have been assigned an absolute position with different positions in the space. If you keep all of them the same with same left, top, width, and height, then you would achieve what you require.

Rups
  • 629
  • 1
  • 8
  • 19
  • Here's a [fiddle](http://jsfiddle.net/U8Fdh/) for this suggestion. Not sure what you mean about assigning all the body parts the same absolute positions - with the current positioning they appear in the right places. – Stuart Dec 11 '12 at 09:20
  • The reason is that once you select a li element, its content will always be displayed. Now when you hover over the other li elements, they would show up, but behind them the selected li element's text is also seen. So if we assign the same absolute positions, it would solve the problem. – Rups Dec 11 '12 at 17:56
  • I can't see how assigning them the same absolute positions would solve this problem of overlapping text. – Stuart Dec 11 '12 at 18:51
  • The background-color attribute to the span element would cover the selected li element. Also the left, top, right and bottom positions should be same for the span elements. – Rups Dec 11 '12 at 19:06
  • Adding the height css for the selected li's span and the span which is hovered would also solve the same problem. – Rups Dec 11 '12 at 19:30
1

I don't think either of the previous answers quite do what you were looking for. This is my suggestion. Note that the CSS is altered as well as javascript added at the end.

<html>
<head><style type="text/css">
#bodysystem-excretory {
     width: 618px; height: 504px;
     background: url("excretory.png") no-repeat;
     margin: 10px auto; padding: 0;
     position: relative;
     border: 1px solid #999;
}
#bodysystem-excretory li {
    margin: 0; padding: 0;
    list-style: none;
    display: block;
    position: absolute;
}
#bodysystem-excretory a {
    display: block;
    /*  text-indent: -9999px;*/
    text-decoration: none;
}
#esoph {
    left: 85px; top: 41px;
    width: 46px; height: 94px;
    z-index: 10;
}
#lungs {
    left: 76px; top: 84px;
    width: 84px; height: 68px;
    z-index: 20;
}
#bladder {
    left: 87px; top: 148px;
    width: 64px; height: 104px;
    z-index: 30;
}
#esoph a {
    height: 94px;
}
#lungs a {
    height: 67px;
}
#bladder a {
    height: 104px;
}
#esoph:hover, #esoph.selected {
    background-image: url("excretory.png") no-repeat -25px -561px;
}
#lungs:hover, #lungs.selected {
    background-image: url("excretory.png") no-repeat -105px -523px;
}
#bladder:hover, #bladder.selected {
    background-image: url("excretory.png") no-repeat -114px -618px;
}
.info span{ 
    display: none
}
.info{
    position:relative;
    z-index:1124;
    color:#000;
}
.selected .info{
    z-index:1125;
}
.selected .info span {
    display:block; position:absolute;
    top:-30px; left:155px;
    width:370px;
    color:#000; background-color:#FFFFFF;
}​</style></head>
<body>
<ul id="bodysystem-excretory">
<li id="esoph">
<a href="#" class="info">
<span id="esoph-info"><h3>Esophagus</h3>
<p>
This is esophagus information. This is esophagus information. 
This is esophagus information. This is esophagus information.
This is esophagus information. This is esophagus information.
This is esophagus information. </p></span></a>
</li>
<li id="lungs"><a href="#" class="info">
<span id="lungs-info"><h3>Lungs</h3></span></a>        
</li>
<li id="bladder"><a href="#" class="info">
<span id="bladder-info"><h3>Bladder</h3>
</span></a></li>
</ul>​<script type="text/javascript">
// Get the <li> elements as a list called 'parts'
var parts = 
    document.getElementById('bodysystem-excretory').getElementsByTagName('li');
function getClickFunction(part) {
    return function() {
// This is the function that will be called when one of the <li>s is clicked
        if (part.className == 'selected') {    // if the body part is already selected
            part.className = '';               // ... then deselect it
        }
        else {                                 // otherwise,
            // first deselect all of the body parts
            for (var i = 0; i < parts.length; i++) {
                parts[i].className = '';
            }
            // then select the one that's been clicked
            part.className = 'selected';
        }
    }
}
// Now, attach this function to all of the <li> elements representing body parts      
for (var i = 0; i < parts.length; i++) {
    parts[i].onclick = getClickFunction(parts[i]);
}​
</script></body></html>
Stuart
  • 9,597
  • 1
  • 21
  • 30
0

You could add a click event which looks at what we clicked on and then changes the style permanently on clicking. This would then 'reveal' the new part permanently.

Your HTML:

<li id="lungs" onclick="highlight(this.id)">
   <!--some stuff-->
</li>

And in javascript (to keep things simple, I've put it into <script> tags, just add this + your other cases into your header somewhere):

 <script> 
   function highlight(id) {
       var part = document.getElementById(id);
       switch(id){
          case "lungs":
             part.style.backgroundImage="url(excretory.png)";
             part.style.backgroundRepeat="no-repeat";
             part.style.backgroundPosition="-105px 523px";
             break;
          //rinse repeat for all cases, don't forget the : after your case and to add break; at the end of each line
          default:
             //do nothing, or something, whatever
    }
 </script>

You can learn more about javascript switch statements here.

agryson
  • 297
  • 2
  • 9
0

I think the most elegant way to go about is having two background images for each organ, [organ].png and [organ]_hover.png. then create one hover event for all the organs by applying the same class to all of them (like .organ);

at this point you can use the .css() function of JQuery to change the background of the specific organ (after getting it by using $(this).attr("id")) by adding the _hover suffix to it.

You should also maintain record of the current organ, so whenever the user hovers over a new organ, you change the previous organ's background back to [organ].png, and then save the new organ as the current one.

As for the info, just use the organ name you already fetched to make it display:block;, and the previous one display:none;

EDIT: here is a fiddle demonstrating the core functionality

HTML:

   <div id="human_body">
            <div class="organ" id="lungs"></div>
            <div class="organ" id="liver"></div>
            <div class="organ" id="pancreas"></div>
            <div class="organ" id="heart"></div>
            <div class="organ" id="kidneys"></div>
        </div>        
        <div id="info">
            <div id="lungs_info">
                Lungs
            </div>
            <div id="pancreas_info">
                Pancreas
            </div>
            <div id="liver_info">
                Liver
            </div>
            <div id="heart_info">
                Heart
            </div>
            <div id="kidneys_info">
                Kidneys
            </div>
        </div>

CSS:

.organ {
width:40px;
    height:40px;
    margin:10px;
}

#lungs {
        background:url("http://www.fishweb.co.il/organs/lungs.png");
    }
    #heart {
        background:url("http://www.fishweb.co.il/organs/heart.png");
    }
    #pancreas {
        background:url("http://www.fishweb.co.il/organs/pancreas.png");
    }
    #kidneys {
        background:url("http://www.fishweb.co.il/organs/kidneys.png");
    }
    #liver {
        background:url("http://www.fishweb.co.il/organs/liver.png");
}

#info>div {
display:none;
}

​ ​JS (JQuery):

var current='';
$(".organ").mouseover(
 function(){
     if (current!='') {
         $("#" + current).css("background","url(http://www.fishweb.co.il/organs/" + current +".png)"); // remove the highlight from the prev organ
         $("#" + current + "_info").hide();
     }
     current = $(this).attr("id");
     $(this).css("background","url(http://www.fishweb.co.il/organs/" + current +"_hover.png)"); // highlight the current organ
     $("#" + current + "_info").show();
 }
    );​
Matanya
  • 6,233
  • 9
  • 47
  • 80
  • I'm a bit confused as to why you would need to get the id. – Stuart Dec 11 '12 at 09:09
  • You need the ID in order to determine which organ was hovered (you can't just use the contextual `this` keyword because each organ has it's own hover image). I've added a fiddle to my answer to demonstrate the core functionality. – Matanya Dec 11 '12 at 14:33
  • Thanks, I see... so it's actually for the 'info' text rather than to change the background image. – Stuart Dec 11 '12 at 15:38
  • No. It's for the background image too. look at the fiddle. – Matanya Dec 11 '12 at 18:32
  • Thanks, now I *actually* see. I wouldn't do it this way for a couple of (not hugely important but sometimes significant) reasons - (i) need to include the image urls in both javascript and css which can get messy and (ii) mouseover initially causes the image to disappear while the '..._hover.png' image is loading. – Stuart Dec 11 '12 at 18:44
  • as for reason (ii), this can be easily fixed with image preload. – Matanya Dec 11 '12 at 18:48
0

You need to create a simple set of identifiers on the links and containers which correspond with each other.

JSFiddle: http://jsfiddle.net/Y4Wtn

<style>
    .btn {font-weight:normal}
    .btn.active {font-weight:bold;}
    .pane {display:none;border:1px #ccc solid;padding:10px;}
    .pane.active {display:block;}
</style>
<script>
// insert jquery here
$(document).read(function(){

    $('.btn').click(function(){
        // grab the rel value of the the link that was clicked
        var thisRel = $(this).attr('rel');
        // remove active class from all .btn
        $('.btn').removeClass('active');
        // add active class to link that was clicked
        $(this).addClass('active');
        // remove all active classes from .pane
        $('.pane').removeClass('active');
        // add class active to pane with the same rel value clicked link
        $('.pane[rel="'+thisRel+'"]').addClass('active');         
    });

});
</script>
<ul>
    <li><a href="#1" class="btn active" rel="1">Item One</a></li>
    <li><a href="#2" class="btn" rel="2">Item Two</a></li>
    <li><a href="#3" class="btn" rel="3">Item Three</a></li>
</ul>

<div class="pane active" rel="1">Pane One</div>
<div class="pane" rel="2">Pane Two</div>
<div class="pane" rel="3">Pane Three</div>
BenMorel
  • 34,448
  • 50
  • 182
  • 322
Alan Mabry
  • 167
  • 1
  • 5
  • For the OP (who *doesn't know anything about Javascript*) it should probably be mentioned that this uses a [library called jQuery](http://jquery.com/) – Stuart Dec 11 '12 at 09:05
  • Thank you @Stuart for pointing that out. I love that this is my first comment. Let's hope, for your and my sake, readers at least know that much or what is the point. – Alan Mabry Dec 13 '12 at 17:10
  • Ha, well, I don't think you can take that for granted. Most beginners' resources on Javascript don't mention jQuery. – Stuart Dec 13 '12 at 17:16