I want to construct an SVG image containing components which reveal additional content on mouse-over.

I've managed this using css to set the visibility style to visible for a target object, based on mouseover of a sibling trigger object.

What I'd now like to do is fix the visibility attribute on click - such that clicking elsewhere resets the visibility back to hidden. If I can get that to work, then I'd be able to reveal content on click for multiple elements, without resorting to any javascript.

I have considered recoding this using form objects like radio buttons etc, but would prefer the layout flexibility provided by raw SVG, since I want to be able to position the active elements as precisely as possible.

The below reveals a callout-type box, but does so only on mouseover. Clicking to set the focus to the trigger circle does have the effect of restyling the callout box, but I want the visibility to remain 'sticky' so that once the mouse stops hovering, it remains visible. Currently, on moving the mouse away from the circle, the callout box disappears.

<svg width="450" height="300">
    <style>
    #text_box_test{
    fill:#FFAAAA;
    }
    
    #hover_thing:hover ~ #text_box_test {
    visibility:visible;
    }
    
    #hover_thing:active ~#text_box_test {
    visibility:visible;
    fill:#AAFFAA;
    }
    
    div.white {
    #background-color:#FFFFFF;
    overflow-y: scroll;
    height: 100%;
    width: 100%;
    }
    
    a:focus ~ #text_box_test {
    fill: #77BBFF;
    fill-opacity: 1.0;
    outline: none;
    visibility:visible;
}
    </style>
    <g>
    <a id="hover_thing" xlink:href="#" tabindex="1">
    <circle id="hover_thing" cx="15" cy="150" r="10" stroke="black" stroke-width="3" fill="red" data-Name="shape 1" data-tabindex="0"/>
    </a>
            
            <g id="text_box_test" visibility="hidden">
            <path 
            stroke-width="3" 
            stroke="black"
            stroke-linejoin="miter"
            fill-opacity="0.85"
                  d="M 20 150 
                     l 40 -15
                     l 0 -75
                     a 10 10 0 0 1 10 -10
                     l 250 0
                     a 10 10 0 0 1 10 10
                     l 0 150
                     a 10 10 0 0 1 -10 10
                     l -250 0
                     a 10 10 0 0 1 -10 -10
                     l 0 -45 z"/>
            <foreignObject x="70" y="60" width="250px" height="150px">
            <div xmlns="http://www.w3.org/1999/xhtml" class="white">
                <h1 xmlns="http://www.w3.org/1999/xhtml">Header Shmeader</h1>
                <p xmlns="http://www.w3.org/1999/xhtml">Text goes here - If more text goes over a thing, then it wraps around. <br> <br> Any more and it may overflow. </p>
                <p xmlns="http://www.w3.org/1999/xhtml">Freddie was a little fish, his skin was nice and shiny, and everywhere that Freddie went, he tried to not get grimy. </p>
            </div>
            </foreignObject>
        </g>


        </g>
            </g>
    </svg>

N.B. Original code edited to reflect information provided in the answer.

1 Answers

1
jdfink On Best Solutions

It looks like "visible is spelled wrong in your a:focus ~ #text_box_test rule (You may need to add tabindex="1" to your <a> if your focus isn't working).

If you want hover AND click to happen for multiple elements, your best option would be to use javascript. Though it could be done using checkboxes, if you're willing to move away from SVG, as demonstrated here:

https://codepen.io/anon/pen/VNqyQY?editors=1100