I just started playing with SVG today and I can't figure out how to do hovering with non-rectangular shapes without having hover area overlap issues, as you can see in my fiddle.
If anyone could point out my missing knowledge I would really appreciate it.
<svg height="444" width="257" class="svg svg1">
<path d="M0 148 L257 0 L257 297 L0 444 Z" style="fill:lime;stroke:none;"
onmouseover="document.getElementById('fade1').style.opacity = '.9';"
onmouseout="document.getElementById('fade1').style.opacity = '0';"/>
</svg>
<svg height="444" width="257" class="svg svg2">
<path d="M0 148 L257 0 L257 297 L0 444 Z" style="fill:lime;stroke:none;"
onmouseover="document.getElementById('fade2').style.opacity = '.9';"
onmouseout="document.getElementById('fade2').style.opacity = '0';"/>
</svg>
<svg height="444" width="257" class="svg svg3">
<path d="M0 148 L257 0 L257 297 L0 444 Z" style="fill:lime;stroke:none;"
onmouseover="document.getElementById('fade3').style.opacity = '.9';"
onmouseout="document.getElementById('fade3').style.opacity = '0';"/>
</svg>
You have to place all of the paths in the same SVG in order to have the hover effects work like you desire. This is due to the SVG elements (not the paths) overlapping each other, which with Z-indexes doesn't work like you want it to
With that being said, you can't position <path>s very easily, so I used this tool to apply the styles you had. Alternatively you could put them in individual <g> elements and position them that way
The other thing to note is you should apply the :hover effects to the paths, not the SVG element
/* SVG */
<svg height="1150" width="257">
<path d="M0 244L257 96L257 393L0 540z" style="fill:lime;stroke:none;"/>
<path d="M0 545L257 397L257 694L0 841z" style="fill:lime;stroke:none;"/>
<path d="M0 846L257 698L257 995L0 1142z" style="fill:lime;stroke:none;"/>
</svg>
/* CSS */
svg {
margin:0 auto;
display:block;
width:257px;
}
svg path {
opacity:.3;
}
svg path:hover {
opacity:1;
}
Demo
P.S. I'm assuming the javascripg onmouseovers and onmouseouts are from a failed attempt?
Related
I have the following generated test-SVG (excerpt).
<svg _ngcontent-dhk-c13=""><g _ngcontent-dhk-c13="" hccard="" _nghost-dhk-c12="" ng-reflect-card="[object Object]"><rect _ngcontent-dhk-c12="" id="8261337b-fb4b-4ac9-a213-0d86cc3dc604" width="100" height="100" x="750" y="450"></rect><g _ngcontent-dhk-c12="" hcedge="" _nghost-dhk-c11="" ng-reflect-edge="[object Object]"><path _ngcontent-dhk-c11="" stroke="black" stroke-width="2" d="M 750 450 L 750 600 Z"></path></g><g _ngcontent-dhk-c12="" hcedge="" _nghost-dhk-c11="" ng-reflect-edge="[object Object]"><path _ngcontent-dhk-c11="" stroke="black" stroke-width="2" d="M 750 450 L 750 600 Z"></path></g><!--bindings={
"ng-reflect-ng-for-of": "[object Object],[object Object"
}--></g><!--bindings={
"ng-reflect-ng-for-of": "[object Object],[object Object"
}--></svg>
There should be a <path> element going from 750/450 to 750/600. However nothing is visible. If i move the <path> element outside of its <g> container into the <g> container above that also holds the red <rect>, it is suddenly visible. Any other way to fix this, other than moving the <path> out of the inner <g>?
As #enxaneta said, the rect and path in your SVG are way outside its default viewport. A viewport is the area on your page that the SVG contents are rendered into.
If we use some CSS to make the viewport size visible (light brown area) and make overflow visible, we can see what's happening.
svg {
background-color: linen;
overflow: visible;
transform: scale(0.5);
}
<svg>
<g>
<rect width="100" height="100" x="750" y="450"></rect>
<g>
<path stroke="black" stroke-width="2" d="M 750 450 L 750 600 Z"></path>
</g>
<g>
<path stroke="black" stroke-width="2" d="M 750 450 L 750 600 Z"></path>
</g>
</g>
</svg>
If you want to fix that, you'll need to do one of two things:
Make the viewport bigger
In the example below, I have made the SVG width and height big enough so that the content is now visible. You may need to scroll down and right to see it.
svg {
background-color: linen;
}
<svg width="850" height="600">
<g>
<rect width="100" height="100" x="750" y="450"></rect>
<g>
<path stroke="black" stroke-width="2" d="M 750 450 L 750 600 Z"></path>
</g>
<g>
<path stroke="black" stroke-width="2" d="M 750 450 L 750 600 Z"></path>
</g>
</g>
</svg>
Tell the browser where in the SVG your elements are, so that it can draw them inside the viewport. You do this by adding a viewBox.
In the example below, I've chosen viewBox values that define the boundaries of the content. The browser is scaling and moving that content so that it fits in the viewport.
svg {
background-color: linen;
width: 400px;
height: 400px;
}
<svg viewBox="750 450 100 150">
<g>
<rect width="100" height="100" x="750" y="450"></rect>
<g>
<path stroke="black" stroke-width="2" d="M 750 450 L 750 600 Z"></path>
</g>
<g>
<path stroke="black" stroke-width="2" d="M 750 450 L 750 600 Z"></path>
</g>
</g>
</svg>
I am trying to use SVGs as CSS background images, and have everything working except for importing external files with use.
Here is what I have:
CSS and HTML:
.shape1 {
background: url("shapes/shape1.svg") no-repeat;
}
<div class="shape1"></div>
Then the shapes/shape1.svg file:
<svg viewBox="0 0 100 200" xmlns="http://www.w3.org/2000/svg">
<path d="
M 10 10
l 0 180
" fill="none" stroke="#000" stroke-width="1px"/>
<use href="parts/part1.svg#build"/>
</svg>
It references the parts/part1.svg file, which contains this:
<svg viewBox="0 0 100 200" xmlns="http://www.w3.org/2000/svg">
<defs>
<path id="build" d="
M 90 10
l 0 180
" fill="none" stroke="#000" stroke-width="1px"/>
</defs>
</svg>
However, when I render everything, it only displays one line, not two.
I've tried a few things. I've tried removing the defs and just loading directly, like this:
<svg viewBox="0 0 100 200" xmlns="http://www.w3.org/2000/svg">
<path d="
M 10 10
l 0 180
" fill="none" stroke="#000" stroke-width="1px"/>
<use href="parts/part1.svg"/>
</svg>
<svg viewBox="0 0 100 200" xmlns="http://www.w3.org/2000/svg">
<path d="
M 90 10
l 0 180
" fill="none" stroke="#000" stroke-width="1px"/>
</svg>
I've also tried messing with the file paths. My directory structure is this:
index.html
shapes/
shapes/shape1.svg
parts/
parts/part1.svg
I've tried ../parts/part1.svg, etc.. Also, I am running this directly from the filesystem, so the path is: file:///Users/me/Desktop/test/index.html. I am getting no errors in the web console. Any help would be appreciated!
I am on Chrome and only care about this working on Chrome for now.
When SVG is used as an image the SVG file must be self-contained for privacy reasons.
So shape1.svg cannot access anything outside itself. You'd have to embed part1.svg into shape1.svg.
Alternatively don't use SVG as a background image, embed it via an object or iframe tag or have it inline.
I have a curved svg line like this
<path d="M70,260 C105,260 126,330 160,330"
style="stroke: #ff4444;stroke-width:2; fill:none;"/>
what I want is to add another svg (like https://www.flaticon.com/free-icon/play-button_149657) in the middle of my line pointing to the end point.
any ideas?
One way to achieve the result is a degenerate animation:
Define the marker shape (obj1 in the example below)
Position the marker at the beginning of the curve (track1 below; this is the path definition from your example).
Specify an animated motion of the marker shape along the curve with some particular settings:
Explicit positioning along the track using keyTimes, keyPoints attributes, limiting the range of positions to exactly one point: the midpoint of the curve
Infinite duration, infinite repeat
Auto-rotation of the shape according to the orientation of the track curve ( rotate attribute )
Effectively there is no animation at all but the shape is positioned at the center of the curve, properly oriented.
Example
<html>
<head>
<title>SVG object centered on path</title>
</head>
<body>
<svg width="200px" height="200px"
viewBox="0 0 500 500"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<defs>
<path
id="obj1"
d="M11.18,0 L-2.5,10 -2.5,-10 Z"
stroke="black" stroke-width="1" fill="green"
>
</path>
<path
id="track1"
d="M70,260 C105,260 126,330 160,330"
stroke="#ff4444" stroke-width="2" fill="none"
/>
</defs>
<use xlink:href="#track1"/>
<use xlink:href="#obj1">
<animateMotion
calcMode="linear"
dur="infinite"
repeatCount="infinite"
rotate="auto"
keyPoints="0.5;0.5"
keyTimes="0.0;1.0"
>
<mpath xlink:href="#track1"/>
</animateMotion>
</use>
</svg>
</body>
</html>
There are a number of ways to do this.
One way is to "cheat" a little and use a <textPath> and an arrow character.
SVG marker-mid on specific point on path
This is a little hacky, and may not work reliably on all browsers, but it may be good enough for your needs.
Another way is split the path in two (using De Casteljau's algorithm), and use a <marker>.
<svg viewBox="0 200 200 200" width="400">
<defs>
<marker id="Triangle"
viewBox="0 0 10 10" refX="0" refY="5"
markerUnits="strokeWidth"
markerWidth="4" markerHeight="3"
orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" />
</marker>
</defs>
<path d="M 70,260
C 87.5,260 101.5,277.5 115.375,295
C 129.25,312.5 143,330 160,330"
style="stroke: #ff4444; stroke-width:2; fill:none; marker-mid:url(#Triangle)"/>
</svg>
There are other ways using Javascript. For example, you could use the SVGPathElement.getPointAtLength() method to find the coordinates of the centre of the path. Then position a triangle at that location.
Is there any possible way to get/find the border radius of an SVG?
Specifically, the rounded corners.
Example:
<svg width="266" height="185" viewBox="-1.5 0 71 48">
<path fill="currentColor" style="stroke: #0059dd; stroke-width:1px;color:black;" d="M66.52,7.74c-0.78-2.93-2.49-5.41-5.42-6.19C55.79,.13,34,0,34,0S12.21,.13,6.9,1.55 C3.97,2.33,2.27,4.81,1.48,7.74C0.06,13.05,0,24,0,24s0.06,10.95,1.48,16.26c0.78,2.93,2.49,5.41,5.42,6.19 C12.21,47.87,34,48,34,48s21.79-0.13,27.1-1.55c2.93-0.78,4.64-3.26,5.42-6.19C67.94,34.95,68,24,68,24S67.94,13.05,66.52,7.74z" fill="#000000" ></path><path d="M 45,24 27,14 27,34" fill="#0059dd"></path>
</svg>
I try to render a SVG polygon filled with pattern. SVG.path filled with pattern doesn't work. As you can see in this jsfiddle, filled background shows up transparent in Firefox and black in Chrome.
The example is based on leaflet GeoJSON Example and uses the diagonalHatch pattern described by carto.net.
<defs>
<pattern id="diagonalHatch" patternUnits="userSpaceOnUse" x="0" y="0" width="105" height="105">
<g style="fill:none; stroke:black; stroke-width:1">
<path d="M0 90 l15,15"/><path d="M0 75 l30,30"/>
<path d="M0 60 l45,45"/><path d="M0 45 l60,60"/>
<path d="M0 30 l75,75"/><path d="M0 15 l90,90"/>
<path d="M0 0 l105,105"/><path d="M15 0 l90,90"/>
<path d="M30 0 l75,75"/><path d="M45 0 l60,60"/>
<path d="M60 0 l45,45"/><path d="M75 0 l30,30"/>
<path d="M90 0 l15,15"/>
</g>
</pattern>
</defs>
As this jsfiddle shows, copying the SVG polygons below the map, makes it work on Chrome but not on Firefox. Apply a fill pattern adding this style to SVG.path:
style="fill: url(#diagonalHatch)"
I'm really not sure if this is a bug in leaflet or some conflict with SVG implementation on Firefox and Chrome.
I've wrote a leaflet plugin for this, you may try it,
https://github.com/lnaweisu/leaflet-polygon-fillPattern
Maybe you can try setting the path via the shape's attribute as mentioned in this thread: Leaflet polygon with fuzzy outline
// Set filter attribute on the polygon
polygon._path.setAttribute('filter', 'url(#blur)');