I'm dynamically changing a cursor to a local svg on hover with
$(element).on('mouseover', function () {
$(this).css('cursor', 'url(svgs/pointer.svg) 9 30 auto');
};
Thats working fine but I'd like to select that svg to manipulate its fill color.
Is there any way to do this so I don't have to make a bunch of different svgs with different fills?
Thanks
You can use inline SVG. Just open your SVG file with your text editor. Copy the XML and use it instead. Just change the fill value and reassign it to the element.
cursor: url('data:image/svg+xml;utf8,<svg fill="%23FF0000" height="48" viewBox="0 0 24 24" width="48" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg>') 24 24, auto;
When using this technique you should escape special chars in the data. Some people prefer to Base64 their images but for SVG you don't need it. In the example above I only had to replace # in the fill value with %23.
button {
cursor: url('data:image/svg+xml;utf8,<svg fill="%23FF0000" height="48" viewBox="0 0 24 24" width="48" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg>') 24 24, auto;
}
button { padding: 30px; }
<button>Hover<br>Here</button>
Related
I'm trying to announce the meaning of each donutchart(svg) arc/section when tab on it by using aria-describedby / aria-labelledby.
Added id to div which is the content needs to be announced.
Added aria-describedby / aria-labelledby with the same string as id to svg path.
Added tabindex = "0" to svg path.
Tested on the MacOS VoiceOver with Chrome/Safari and iPhone ios VoiceOver with Safari.
When tab on the arc/section, the VoiceOver will only announce graphic symbol instead of the content of div. However, the announced content is ignored no matter using aria-describedby / aria-labelledby.
<svg class="donut-chart" width="236px" viewBox="0 0 236 236">
<g class="donut-chart-arcs">
<path class="donut-chart-path" d="M118,218.3
A100.3, 100.3 0 0 1 117.50623649597293, 218.29878462674455
L117.63984309118025,191.15911349244897
A73.16, 73.16 0 0 0 118, 191.16 z" stroke="#ffffff" stroke-width="2px" fill="#0046ad" opacity="1" tabindex="0" aria-describedby="0.28"></path>
<path class="donut-chart-path" d="M117.50623649597293,218.29878462674455
A100.3, 100.3 0 0 1 33.32260328573676, 171.757124976093
L56.23531063194917,157.21107939432665
A73.16, 73.16 0 0 0 117.63984309118025, 191.15911349244897 z" stroke="#ffffff" stroke-width="2px" fill="#ec0439" opacity="1" tabindex="0" aria-describedby="56.89"></path>
<path class="donut-chart-path" d="M33.32260328573676,171.757124976093
A100.3, 100.3 0 0 1 63.65981518807381, 33.695585438212646
L78.36362990188914,56.5073682019904
A73.16, 73.16 0 0 0 56.23531063194917, 157.21107939432665 z" stroke="#ffffff" stroke-width="2px" fill="#1977d3" opacity="1" tabindex="0" aria-describedby="88.95"></path>
<path class="donut-chart-path" d="M63.65981518807381,33.695585438212646
A100.3, 100.3 0 0 1 173.18230621846504, 34.244384782800665
L158.25062335935098,56.907668900395784
A73.16, 73.16 0 0 0 78.36362990188914, 56.5073682019904 z" stroke="#ffffff" stroke-width="2px" fill="#7300cd" opacity="1" tabindex="0" aria-describedby="65.7"></path>
<path class="donut-chart-path" d="M173.18230621846504,34.244384782800665
A100.3, 100.3 0 0 1 117.99999999999994, 218.3
L117.99999999999996,191.16
A73.16, 73.16 0 0 0 158.25062335935098, 56.907668900395784 z" stroke="#ffffff" stroke-width="2px" fill="#aa00aa" opacity="1" tabindex="0" aria-describedby="145.55"></path>
</g>
</svg>
<div id="0.28">$0.28</div>
<div id="56.89">$56.89</div>
<div id="88.95">$88.95</div>
<div id="65.7">$65.7</div>
<div id="145.55">$145.55</div>
announce the content in div
I’m not able to test in VoiceOver, but I’ll provide an answer based on the standards.
You must name focusable elements
If you allow focus on these elements, they must have an accessible name, provided by aria-label or aria-labelledby.
A description is only optionally read by screen readers, which is a configuration choice. You might provide one additionally, but not as the only text.
You must not name path elements without a role
The ARIA standard forbids to name elements with certain roles.
It‘s unclear which role a SVG path element has implicitly, since there is no ARIA in SVG standard. It might have role="none" which is a synonym for the presentation role, which in turn must not be named. This is the case in Firefox.
Which role to use for your path?
So the question follows which role should you use.
The standard to refer to here would be the W3C Recommendation WAI-ARIA Graphics Module.
So it seems that Safari might take its interpretation from this recommendation, when announcing graphic symbol. The standard says:
A graphical object used to convey a simple meaning or category, where the meaning is more important than the particular visual appearance. It may be a component of a larger structured graphic such as a chart or map.
(Emphasis mine)
The SVG–Aria Element Mapping Table also maps <path> to graphics-symbol if it should be included in the accessibility tree.
Reasons to include the element are aria-label and tabindex attributes.
In the W3C Wiki there also is an older page called SVG Accessibility/ARIA roles for charts. The corresponding role for your chart would probably be graphics dataunit:
A distinct data value in a chart or map.
Since the Wiki page never made it to a Recommendation, you could follow the standard’s suggestion to provide a aria-roledescription to approach the wiki role:
<path role="graphics-symbol" aria-roledescription="dataunit">
If you check out Highcharts’ Donut chart, you might notice that they use <path role="img" aria-label="…">.
Focus or not?
It’s unclear whether or not you should make these data units focusable. It might be preferable to not navigate within simple charts, doing so in more complex charts most probably improves comprehension of the data groups.
You should test with screen reader users.
In general, only interactive elements that can be clicked, should be focusable. Or put the other way around:
Focusable elements should have interactive semantics
If elements are focusable, focus needs to be visible, so you’ll need to add a :focus style as well.
If you have bigger charts than that one, it would be better to provide a single tab stop, as explained in Keyboard Navigation Inside Components.
Arrow keys then allow to focus single data units.
Again, Highcharts provide a good example for this.
Watch out for . in IDs
It’s not a good practice to use periods . in IDs, as MDN warns:
. has a special meaning in CSS (it acts as a class selector). Unless you are careful to escape it in the CSS, it won't be recognized as part of the value of an id attribute. It is easy to forget to do this, resulting in bugs in your code that could be hard to detect.
Playground
<svg class="donut-chart" width="236px" viewBox="0 0 236 236">
<g class="donut-chart-arcs">
<path class="donut-chart-path" d="M118,218.3
A100.3, 100.3 0 0 1 117.50623649597293, 218.29878462674455
L117.63984309118025,191.15911349244897
A73.16, 73.16 0 0 0 118, 191.16 z" stroke="#ffffff" stroke-width="2px" fill="#0046ad" opacity="1" tabindex="0" aria-labelledby="0-28" role="img"></path>
<path class="donut-chart-path" d="M117.50623649597293,218.29878462674455
A100.3, 100.3 0 0 1 33.32260328573676, 171.757124976093
L56.23531063194917,157.21107939432665
A73.16, 73.16 0 0 0 117.63984309118025, 191.15911349244897 z" stroke="#ffffff" stroke-width="2px" fill="#ec0439" opacity="1" tabindex="0" aria-labelledby="56-89" role="graphics-symbol" aria-roledescription="dataunit"></path>
<path class="donut-chart-path" d="M33.32260328573676,171.757124976093
A100.3, 100.3 0 0 1 63.65981518807381, 33.695585438212646
L78.36362990188914,56.5073682019904
A73.16, 73.16 0 0 0 56.23531063194917, 157.21107939432665 z" stroke="#ffffff" stroke-width="2px" fill="#1977d3" opacity="1" tabindex="0" aria-describedby="88.95"></path>
<path class="donut-chart-path" d="M63.65981518807381,33.695585438212646
A100.3, 100.3 0 0 1 173.18230621846504, 34.244384782800665
L158.25062335935098,56.907668900395784
A73.16, 73.16 0 0 0 78.36362990188914, 56.5073682019904 z" stroke="#ffffff" stroke-width="2px" fill="#7300cd" opacity="1" tabindex="0" aria-describedby="65.7"></path>
<path class="donut-chart-path" d="M173.18230621846504,34.244384782800665
A100.3, 100.3 0 0 1 117.99999999999994, 218.3
L117.99999999999996,191.16
A73.16, 73.16 0 0 0 158.25062335935098, 56.907668900395784 z" stroke="#ffffff" stroke-width="2px" fill="#aa00aa" opacity="1" tabindex="0" aria-describedby="145.55"></path>
</g>
</svg>
<div id="0-28">$0.28</div>
<div id="56-89">$56.89</div>
<div id="88-95">$88.95</div>
<div id="65-7">$65.7</div>
<div id="145-55">$145.55</div>
Looking for the solution that will allow me to easily manage the dynamically injected text (with unknown length) in the svg rect / circle area.
Currently, designer generates for me svg via using AI and other design software.
In generated code, the position of the text elements is determined by coordinates what means that each and every text length change forces the developer to change coordinates manually to keep appropriate alignment.
Is there a generic way to be independent of the length of the text and always align it properly in the middle (horizontally and vertically)?
Below code example and its visualization.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 1106.3 443" style="enable-background:new 0 0 1106.3 443;" xml:space="preserve">
<style>
.rect-header { fill: #AAA; }
.rect-bg { fill: #CCC; }
</style>
<rect class="rect-header" width="1106.3" height="39.9"/>
<rect y="39.7" class="rect-bg" width="553.2" height="32.7"/>
<rect y="72.4" class="rect-bg" width="553.2" height="32.7"/>
<rect x="553.2" y="39.7" class="rect-bg" width="553.2" height="32.7"/>
<rect x="553.2" y="72.4" class="rect-bg" width="553.2" height="32.7"/>
<text transform="matrix(1 0 0 1 525.1992 25.7028)">HEADER</text>
<text transform="matrix(1 0 0 1 235.1992 60.7028)">48.1</text>
<text transform="matrix(1 0 0 1 815.0431 60.7029)">103</text>
<text transform="matrix(1 0 0 1 810.2572 93.731)">ABC</text>
<text transform="matrix(1 0 0 1 229.0706 93.7309)">DEFG</text>
</svg>
SVG example visualization
Use text-anchor="middle" to specify that the text should be centred on the coordinates you supply, rather than start there.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" viewBox="0 0 1106.3 443">
<style>
.rect-header { fill: #AAA; }
.rect-bg { fill: #CCC; }
</style>
<rect class="rect-header" width="1106.3" height="39.9"/>
<rect y="39.7" class="rect-bg" width="553.2" height="32.7"/>
<rect y="72.4" class="rect-bg" width="553.2" height="32.7"/>
<rect x="553.2" y="39.7" class="rect-bg" width="553.2" height="32.7"/>
<rect x="553.2" y="72.4" class="rect-bg" width="553.2" height="32.7"/>
<g text-anchor="middle">
<text x="553.2" y="25.7">HEADER</text>
<text x="276.6" y="60.7">48.1</text>
<text x="829.8" y="60.7">103</text>
<text x="829.8" y="93.7">ABC</text>
<text x="276.6" y="93.7">DEFGHIJKLMNOPQRSTUVWXYZ</text>
</g>
</svg>
If you don't specially need to put the text INSIDE the Svg, you can make the parent postion: relative;, inside it, center the svg with position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) and the same for the text in a global div, it will center no matter the size of the elements.
However, if you want to have the text inside the SVG, i'm sorry, i can't help you
The SVG viewBox size is important. That determines the relative scale. You can see each interior <rect> is sized relative to the viewBox. Total viewBox width is 1106.3, so each rect is half of that at 553.2.
You can add <tspan>'s inside of your <text></text> tags. Set your tspan x and y values starting with 1/2 the viewBox size, less 1/2 the font size. This may require a little tweaking before you get it just right. SVG uses text-align and text-anchor style tags for placement (not position:relative / absolute). Try "text-align: center; text-anchor: middle;"
Often SVGs are created in Adobe Illustrator, Sketch, or other visual applications. As a developer, I often make edits directly in the XML, carefully cutting unnecessary styles, transforms, etc. Don't be afraid to round some numbers, provided you test everything before pushing your code.
I'm an Ubuntu user, so I use Inkscape (which is also available for Mac and Windows). It's a great tool for this, offering a visual layout with a built-in XML editor and properties editors.
I'm trying to create a box that is opaque, but has a block of text in it that you can see through (to like the background image of the page or some element underneath).
It's hard to explain so I've made some crude diagrams:
I am attempting to use SVG files to do this and use Javascript/jquery to modify the rectangle width and height but I'm not proficient at the SVG format... I've managed to piece this together using the evenodd filter:
https://jsfiddle.net/PhoenixFieryn/sqvLgqbq/
<svg id="coverimage" width="80pcm" height="30cm" viewBox="0 0 2000 2000" version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<desc>Example fillrule-evenodd - demonstrates fill-rule:evenodd</desc>
<defs>
<rect x="1" y="1" width="2000" height="1000"
fill="white" stroke="blue" />
</defs>
<g fill-rule="evenodd" fill="white" >
<path d="M0 0 h1000 v1000 h-1000z M841,396.8c-2.4-4-1.6-8.8,2.4-11.2c68-44,95.2-105.6,95.2-172.8c0-116-96.8-205.6-211.2-205.6H610.6H469.8
h-6.4c-4,0-5.6,1.6-8.8,6.4L315.4,320c-4,6.4-8,6.4-11.2,0l-140-306.4c-2.4-4.8-4.8-6.4-8.8-6.4H9c-5.6,0-8.8,4-6.4,9.6l264,554.4
c1.6,4,5.6,6.4,9.6,6.4h66.4c4,0,7.2-1.6,8.8-5.6l110.4-230.8v228.4c0,4.8,3.2,8,8,8h146.4c4.8,0,8-3.2,8-8V426.4c0-4.8,3.2-8,8-8
h42.4c4,0,8,1.6,9.6,5.6l76,148c1.6,4,5.6,5.6,9.6,5.6h158.4c5.6,0,8.8-4,5.6-9.6L841,396.8z M701.8,276h-69.6c-4.8,0-8-3.2-8-8
V158.4c0-4.8,3.2-8,8-8h75.2c36.8,0,68,28.8,68,62.4C775.4,244,750.6,276,701.8,276z"/>
</g>
I don't know how to modify the size/position of the text and rectangle independently well. I can barely understand what I wrote and why the margin is so big.
If anyone could help me, through this or any other method, thank you!
Edit: someone pointed out that there may be a duplicate, but that solution does not work in Firefox unfortunately. I am looking for a cross “platform” solution. But thanks for the link, it’s very helpful nonetheless.
My suggestion is to create a mask using the text. We then create a blue rectangle that we mask with the our text mask.
We can postion the SVG and have it size the way we want using SVG width and height. But we also make the blue rectangle very large and have the SVG set to overflow: visible. This allows us to easily have the SVG size be responsive and also have the blue extend to all the way to the edges of the screen.
body {
background-image: url('http://austinhou.com/img/cover.jpg');
background-size: cover;
margin: 0;
padding: 0;
}
#coverimage {
width: 40%;
height: 100vh;
overflow: visible;
}
<body>
<svg id="coverimage" viewBox="0 0 950 600" preserveAspectRatio="xMinYMid meet">
<defs>
<mask id="vr">
<rect x="0" y="-1000%" width="1000%" height="3000%" fill="white"/>
<path fill="black" d="M841,396.8c-2.4-4-1.6-8.8,2.4-11.2c68-44,95.2-105.6,95.2-172.8c0-116-96.8-205.6-211.2-205.6H610.6H469.8
h-6.4c-4,0-5.6,1.6-8.8,6.4L315.4,320c-4,6.4-8,6.4-11.2,0l-140-306.4c-2.4-4.8-4.8-6.4-8.8-6.4H9c-5.6,0-8.8,4-6.4,9.6l264,554.4
c1.6,4,5.6,6.4,9.6,6.4h66.4c4,0,7.2-1.6,8.8-5.6l110.4-230.8v228.4c0,4.8,3.2,8,8,8h146.4c4.8,0,8-3.2,8-8V426.4c0-4.8,3.2-8,8-8
h42.4c4,0,8,1.6,9.6,5.6l76,148c1.6,4,5.6,5.6,9.6,5.6h158.4c5.6,0,8.8-4,5.6-9.6L841,396.8z M701.8,276h-69.6c-4.8,0-8-3.2-8-8
V158.4c0-4.8,3.2-8,8-8h75.2c36.8,0,68,28.8,68,62.4C775.4,244,750.6,276,701.8,276z" transform="translate(-210 0)"/>
</mask>
</defs>
<rect x="0" y="-1000%" width="1000%" height="3000%" fill="#09f" mask="url(#vr)"/>
</svg>
</body>
JSFiddle version
I need to inline SVG files from urls.
I'm not sure if it is important, but we are using Angular 2
I need to convert this
<img src='svg/workspace.svg'>
into this at runtime
<svg width="100%" height="100%" viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg" fit="">
<path d="M13.95 4.05A7 7 0 1 0 15.93 10H13.9A5 5 0 0 1 4 9a5 5 0 0 1 8.536-3.536L10 8h6V2l-2.05 2.05z" fill-rule="evenodd"></path>
</svg>
Is there a library to do this?
Update
At this point we tried [inlineHTML] from angular, but it "sanitizes" the svg, and we end up with nothing
Update 2 a solution
We gave up and ended using the <use> tag inside the <svg> tag
<svg><use xmlns:xlink="http://www.w3.org/1999/xlink"
attr.xlink:href="svg/{{workspace.svgName}}.svg#icon"
></use></svg>
attr is required because angular2 didn't understand plan xlint:href, the result is similar to inlined SVG, but we have to edit the SVG files to remove width, height and fill tags.
I figured out a problem with SVG I couldn't solve yet. Given is a svg with multiple animations depending on each other with the begin attribute. So the animations got different ID's like 'circle' and begin tags with values like 'circle.end'. These svg is rendered / used multiple times on the page. In the first point is it not valid to have a id multiple times. At the second point all svg's doing the animation depending on circle.end when I start it with circle.beginElement() of the first svg.
So how can I start an animation depending on another animation without using id's or how can I start the animation on only one svg?
Here is a sample code
<svg>
<defs>
<path d="asdasd" id="circle-image">
<animateTransform id="circle" attributeName="transform" type="translate" from="0, 0" to="15, 0" begin="indefinite"/>
<animateTransform attributeName="transform" type="translate" from="15, 0" to="0, 0" begin="circle.end"/>
</path>
</defs>
</svg>
<svg viewBox="0 0 34 24" width="45px" height="24px" class="first">
<use xlink:href="#circle-image"/>
</svg>
<svg viewBox="0 0 34 24" width="45px" height="24px" class="second">
<use xlink:href="#circle-image"/>
</svg>
I want to somehow trigger .first #circle animation and .second #circle animation. The depending animation should only trigger within it's use element and not globally for all.
Can someone help here?
Thanks in advance
Regards Thomas