An SVG with a line (or path) which uses stroke-dasharray only seems to trigger CSS and JS hover events when the user hovers over the solid parts of the dashed line: https://codepen.io/anon/pen/YeXoZy
Is there a simple way to make both the JS and CSS events trigger when the solid or invisible parts of the line are hovered?
My current plan is to draw a second, invisible line following the same path and use it to detect mouse events. https://codepen.io/anon/pen/BYNgRR This seems heavy handed and I'm hoping there's a cleaner way I'm missing.
I'm not sure how to do it without the second "detector" line, but a less heavy handed way is at least possible without the JS.
Switch the order of the lines, then you can use the hover selector as usual for the dashed line, then use + in a selector for the detector line to change the properties of the line immediately following it:
https://codepen.io/RyanGoree/pen/LQVKBV
This can be solved somewhat by using a rect instead of line and using SVG transforms with patterns.
An example can be seen at this CodePen.
It essentially bubbles down to:
<svg height="210" width="500">
<defs>
<pattern id="pattern1"
width="10" height="10"
patternUnits="userSpaceOnUse"
patternTransform="rotate(0 60 60)">
<line stroke="green" stroke-width="12px" y2="10"/>
</pattern>
<pattern id="pattern2"
width="10" height="10"
patternUnits="userSpaceOnUse"
patternTransform="rotate(0 60 60)">
<line stroke="red" stroke-width="12px" y2="10" stroke="transparent"/>
</pattern>
</defs>
<g transform="rotate(45 60 60)">
<rect x="0" y="0" width="500" height="5"/>
</g>
</svg>
And the following CSS:
rect {
fill: url(#pattern1)
}
rect:hover {
fill: url(#pattern2)
}
This is an old topic I know. But found the answer on Css hover sometimes doesn't work on svg paths
If you want to trigger the event only on stroke/visible, use pointer-events: stroke; or pointer-events: visible; (only the stroke) and pointer-events: all; (on both)
Here is a code example:
<body>
<div id="donut-score" class="svg-item" style="display: block;">
<svg width="100%" height="100%" viewBox="0 0 40 40" class="donut">
<circle class="donut-hole" cx="20" cy="20" r="15.91549430918954" fill="#fff"></circle>
<circle class="donut-ring" cx="20" cy="20" r="15.91549430918954" fill="transparent" stroke-width="3.5"></circle>
<circle id="donut-score-part-1" class="donut-segment donut-segment-1" onmousemove="this.style.stroke ='orange';" onmouseout="this.style.stroke = '#ff8197';" cx="20" cy="20" r="15.91549430918954" fill="transparent" stroke-width="3.5" stroke-dasharray="20 80" stroke-dashoffset="25"></circle>
<g class="donut-text-item donut-text-item">
<text y="50%" transform="translate(0, 2)">
<tspan id="donut-score-text" x="50%" text-anchor="middle" class="donut-text">Score </tspan>
<tspan id="donut-score-aantal" x="50%" Y="65%" text-anchor="middle" class="donut-text">0 </tspan>
</text>
</g>
</svg>
</div>
</body>
ccs:
.donut-segment {
stroke: #ff8197;
}
.svg-item {
width:200px;
font-size: 16px;
margin: 0 auto;
}
.donut-text {
font-size: 0.35em;
line-height: 1;
transform: translateY(0.5em);
font-weight: bold;
}
If you add pointer-events: stroke; to the class .donut-segment then it only works on the stroke. If you use non or pointer-events: all it works on both. I tested it in codepen.
If we have a background and a foreground line, using the same dash-array, we can set the x2 value of the 2nd to get a progress-bar looking image.
<svg width="1000" height="40">
<g stroke-width="40" stroke-dasharray="0 5 90 5">
<line stroke="gray" x1="0" x2="1000" y1="20" y2="20" />
<line stroke="green" x1="0" x2="750" y1="20" y2="20" />
</g>
</svg>
But if we change the x2 value, it change size directly, it isn't animated with the css transition: all 0.30s;
Played around with clippath, transform-scale, transform-translate, but can't get it to animate it.
A setInterval may solve it, but would rather have a css soultion.
Can it be done?
I have an image in the format .svg like the one below.
I want to make a webpage where the user can interact with a image like this, but with more nodes. The structure will be similar to a tree.
Is it possible to interact with this .svg image directly, using javascript/html/css?
If so, how?
Note: By interact I mean being able to click on the nodes -and the webpage recognizing it- and when one node is selected the color of the other nodes change.
Note2: I just have the .svg file, I don't know if I'm able to define this as a inline svg on html.
Note3: This image will have many nodes (80+), so I would rather not having to define a clickable area for each one of them and so on... But if this is the only solution, no problem.
Edit:
Here is the content of my .svg file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: g Pages: 1 -->
<svg width="134pt" height="116pt"
viewBox="0.00 0.00 134.00 116.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 112)">
<title>g</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-112 130,-112 130,4 -4,4"/>
<!-- a -->
<g id="node1" class="node"><title>a</title>
<ellipse fill="none" stroke="black" cx="27" cy="-90" rx="27" ry="18"/>
<text text-anchor="middle" x="27" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">a</text>
</g>
<!-- b -->
<g id="node2" class="node"><title>b</title>
<ellipse fill="none" stroke="black" cx="27" cy="-18" rx="27" ry="18"/>
<text text-anchor="middle" x="27" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">b</text>
</g>
<!-- a->b -->
<g id="edge1" class="edge"><title>a->b</title>
<path fill="none" stroke="black" d="M27,-71.6966C27,-63.9827 27,-54.7125 27,-46.1124"/>
<polygon fill="black" stroke="black" points="30.5001,-46.1043 27,-36.1043 23.5001,-46.1044 30.5001,-46.1043"/>
</g>
<!-- c -->
<g id="node3" class="node"><title>c</title>
<ellipse fill="none" stroke="black" cx="99" cy="-18" rx="27" ry="18"/>
<text text-anchor="middle" x="99" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">c</text>
</g>
<!-- b->c -->
<g id="edge2" class="edge"><title>b->c</title>
<path fill="none" stroke="black" d="M54,-18C56.6147,-18 59.2295,-18 61.8442,-18"/>
<polygon fill="black" stroke="black" points="61.9297,-21.5001 71.9297,-18 61.9297,-14.5001 61.9297,-21.5001"/>
</g>
</g>
</svg>
The SVG would need to be inline to have interaction on a page. If you embed an image then the image (.svg) is treated as a single object. For the inline SVG each node should have a separate ID if you want to select them individually.
Here's one I created for another answer.
svg {
display: block;
width: 20%;
margin: 25px auto;
border: 1px solid grey;
stroke: #006600;
}
#buttons polygon:hover {
fill: orange;
}
#buttons rect:hover {
fill: blue
}
#center {
fill: #00cc00;
}
#top {
fill: #cc3333;
}
#right {
fill: #663399;
}
#left {
fill: #bada55;
}
<svg viewbox="0 0 100 100">
<g id="buttons">
<rect id="center" x="25" y="25" height="50" width="50" />
<polygon id="top" points="0,0 100,0 75,25 25,25" />
<polygon id="right" points="100,0 75,25 75,75 100,100" />
<polygon id="bottom" points="0,100 25,75 75,75 100,100" />
<polygon id="left" points="0,0 25,25 25,75 0,100" />
</g>
</svg>
You don't necessarily need to have the svg inline, you could have it in an object tag.
So the html would look like...
<div id="svgdiv">
<object id="svgobject" data="objectclicktest.svg"></object>
</div>
and correspending js
var mySvg = document.getElementById("svgobject").contentDocument.querySelectorAll('svg');
var myNodes = mySvg[0].querySelectorAll('.node');
for( var i = 0; i < myNodes.length; i++ ) {
myNodes[i].addEventListener('click', changeStyle );
}
function changeStyle() {
this.style.fill="blue";
}
Example Click on letters and they should go blue. Note, (I don't think this would work in a setup like a fiddle though)
inline svg elements can interact like other html elements, you can set css rules on them and apply js on them too, you dont need areas
svg is a markup language, meaning that you can use css selector libraries such as jquery to interact with the given svg. You can query the svg in order to get an element by its id, or get an array of elements selected by class. You can attach event handlers to them such as click, mouseover, mouseenter, etc. You can even style them with css.
I notice that svg adds some gradient borders in very tiny pixels around elements. Here's the jsfiddle for it:
http://jsfiddle.net/XrkRT/
<rect x="1" y="1" width="1198" height="398"
fill="none" stroke="blue" stroke-width="10" />
<g stroke="green" >
<line x1="100" y1="300" x2="300" y2="300"
stroke-width="20" fill="none" />
</g>
How do I draw solid color line and rect. It's hard to see with normal zoom. I take a screenshot and zoom it in pixlr.com. Here's the image:
That's antialiasing. You can turn it off with shape-rendering="crispEdges" but be aware that any diagonal lines will look rougher.
I have a series of shapes that I want the user to be able click anywhere on the shape to pick up as part of a drag and drop feature. All of these shapes are bounded by a rectangle.
For example:
<g id="shape1" fill="none" stroke="black">
<rect x="0" y="0" width="100" height="100"/>
<circle cx="50" cy="50" r="50"/>
</g>
<g id="shape2" fill="none" stroke="black">
<rect x="0" y="0" width="100" height="100"/>
<line x1="0" y1="0" x2="50" y2="100"/>
<line x1="100" y1="0" x2="50" y2="100"/>
</g>
I already have all of the drag and drop parts working, the problem is all of these shapes have to have fill="none" so you can see anything that may be underneath of them. This means that even though they are bounded by the rectangle, at the moment users have to physically click on one of the lines in order to pick it up instead of being able to click anywhere on the shape like I want.
My original idea was to use fill="white" and then set opacity="0" or some really low value but this applies to the stroke as well so this didn't work out.
Any ideas on how I can get this working?
Pointer-events is probably what you want here.
Here are some examples:
http://dev.w3.org/SVG/profiles/1.1F2/test/svg/interact-pevents-07-t.svg
http://dev.w3.org/SVG/profiles/1.1F2/test/svg/interact-pevents-08-f.svg
http://dev.w3.org/SVG/profiles/1.1F2/test/svg/interact-pevents-09-f.svg
So it turns out I was a lot closer then I thought. Who knew they had a fill-opacity attribute...
<g id="shape1" fill="white" stroke="black" fill-opacity="0">
<rect x="0" y="0" width="100" height="100"/>
<circle cx="50" cy="50" r="50"/>
</g>
<g id="shape2" fill="white" stroke="black" fill-opacity="0">
<rect x="0" y="0" width="100" height="100"/>
<line x1="0" y1="0" x2="50" y2="100"/>
<line x1="100" y1="0" x2="50" y2="100"/>
</g>