Replace Circle Elements with Icons
I am trying to make my SVG circle elements look like shopping carts. Is there a way to completely replace the definition of a circle element in svg so that it renders a certain icon ?
I'd like
<circle cx="280px" cy="411px" r="4.976112128"></circle>
to look like
<i class="fa fa-shopping-cart"></i>
If not, is there a simpler way to display an icon whenever the circle element is called ?
Thank you very much !
You can try styling the <circle> element with CSS's background-image property:
circle {
background-image: url(http://www.example.com/bck.png);
}
You can define your own elements and call those instead of circles. This way you can still use circles if needed elsewhere.
If you are not looking to use CSS you can use "defs" and "use".
<?xml version="1.0" encoding="utf-8"?>
<!-- from this website http://tutorials.jenkov.com/svg/svg-and-css.html -->
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<defs>
<g id="shopcart">
<image x="499.5" y="242.4" height="40" width="40" id="cart" preserveAspectRatio="none" xlink:href="c:\temp\cart.png" opacity="1" style="pointer-events: none"/>
</g>
</defs>
<use xlink:href="#shopcart" x="10" y="50" transform="translate(150,50)" />
<use xlink:href="#shopcart" x="100" y="250" />
<use xlink:href="#shopcart" x="200" y="250" />
<use xlink:href="#shopcart" x="300" y="250" />
</svg>
Related
I have this model
<svg id=cardModel viewBox="0 0 100 200">
<rect x="0" y="0" width="100" height="200" fill="transparent" stroke="black"></rect>
<text id="text" x="25" y="125" font-size=100>change me</text>
</svg>
and I want to change the text from
<use href="#cardModel"></use>
I tryed using getElementById but as expected the <use> have no child.
Here's a jsFiddle: https://jsfiddle.net/e6gh07fa/316/
(seems like we can't use namespace in SO scripts)
I know I could use Node.cloneNode() but I want to know if there is another way
I want to access the SVG code created by MathJax via javascript. Apparently, MathJax put the SVG <path> under shadow-root, which is not directly accessible by javascript. Here is a picture of the elements given by Chrome
If I get the <svg> element by any javascript method, the <path> children will not be included.
You cannot avoid shadow-root. It is not put there by MathJax renderer. It is because of the use tag.
From MDN:
The <use> element takes nodes from within the SVG document, and duplicates them somewhere else.
So MathJax creates svg pathes and gives them ids and reuses them. Say the letter a is rendered into svg, and MathJax stores it in the svg with an id and use it when the letter a is needed to be rendered.
Below example from MDN speaks better.
<svg width="80" height="80" xmlns="http://www.w3.org/2000/svg">
<style>
.classA {
fill: red;
}
</style>
<defs>
<g id="Port">
<circle style="fill: inherit;" r="10"/>
</g>
</defs>
<text y="15">black</text>
<use x="50" y="10" href="#Port" />
<text y="35">red</text>
<use x="50" y="30" href="#Port" class="classA"/>
<text y="55">blue</text>
<use x="50" y="50" href="#Port" style="fill: blue;"/>
</svg>
Here's a storyboard of the CSS/JS/SVG animation I'm trying to accomplish. Two triangle masks enter from either side, then intersect resulting in a negative mask:
The point where the triangles intersect is where it gets tricky. When I export the mask for panel 4 to SVG, it looks like this:
<svg width="416px" height="289px" viewBox="0 0 416 289" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<path d="M211.503681,65.6626347 L507.009604,-138.787586 L507.009604,425.787586 L211.507182,221.339788 L-84,425.792431 L-84,-138.787586 L211.503681,65.6626347 Z M211.503681,65.6626347 L99,143.5 L211.507182,221.339788 L324.01001,143.502422 L211.503681,65.6626347 Z" id="path-1"></path>
</defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<rect id="Rectangle-1-Copy-3" fill="#F6A623" x="0" y="0" width="416" height="289"></rect>
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use id="Combined-Shape" fill="#000000" xlink:href="#path-1"></use>
<rect id="Rectangle-1-Copy-2" fill="#4990E2" mask="url(#mask-2)" x="0" y="0" width="416" height="289"></rect>
</g>
</svg>
It looks like it's basically drawing two shapes, the negative-space diamond mask in the center and the remainder of the outer triangles.
So the static mask itself appears to be possible with SVG, but I don't know how to animate it. Is there a library that can simplify this kind of SVG transition/tweening, or a fancy math equation that can calculate the paths dynamically?
Or am I looking at this the wrong way entirely and there's a much easier way to do it altogether?
So the solution was to make it both more simple AND more complicated.
Instead of two layers on top of each other with one mask, I needed three layers. One on the bottom to show behind the first mask, the second to be masked by the incoming triangles, and a third layer above that, duplicate to the first, where a diamond-shaped mask is applied.
<svg width="500" height="300" viewbox="0 0 500 300">
<defs>
<clipPath id="triangles">
<path id="left" d="M-250,-150 L250,150 L-250,450 Z" fill="black" />
<path id="right" d="M250,150 L750,-150 L750,450 Z" fill="black" />
</clipPath>
<clipPath id="diamond">
<path id="diamond-path" d="M250,0 L500,150 L250,300 L0,150 Z" fill="black" />
</clipPath>
</defs>
<!-- bottom -->
<g id="bottom">
<rect fill="darkorange" x="0" y="0" width="500" height="300" />
<text x="50%" y="65%" text-anchor="middle" class="text">Text</text>
</g>
<!-- middle/triangles -->
<g id="middle" clip-path="url(#triangles)">
<rect fill="dodgerblue" x="0" y="0" width="500" height="300" />
<text x="50%" y="65%" text-anchor="middle" class="text">Text</text>
</g>
<!-- top/diamond -->
<g id="top" clip-path="url(#diamond)">
<rect fill="darkorange" x="0" y="0" width="500" height="300" />
<text x="50%" y="65%" text-anchor="middle" class="text">Text</text>
</g>
</svg>
The top layer with the diamond path starts out scaled to 0, making it invisible. The two triangle clip paths are animated in towards each other, showing the bottom layer underneath. When the two triangle points meet, the diamond clip path on the top layer is scaled up, revealing the top layer which is a duplicate of the bottom.
I also switched to clip paths instead of masks because they're a) better supported and b) allow for multiple paths.
Here's a Codepen using CSS for the animations (only works in WebKit for the moment).
UPDATE: Here's a Codepen using GSAP that works in all browsers: http://s.codepen.io/kgrote/debug/mPxzZY
Good afternoon everyone,
I'm defining an SVG on my page with the following defs.
<svg width="0" height="0">
<defs>
<g id="stroke-hexagon">
<polygon fill="#002663" stroke="#FFFFFF" stroke-width="6" stroke-miterlimit="12" points="57.8,185 5.8,95 57.8,5 161.8,5 213.8,95 161.8,185 "/>
</g>
<g id="hexagon">
<polygon fill="#006890" points="52,180 0,90 52,0 156,0 208,90 156,180 "/>
</g>
</defs>
</svg>
...and implementing it later in the HTML using this:
<svg width="208px" height="180px" viewBox="0 0 208 180" >
<use xlink:href="#hexagon"></use>
<text class="faicon" x="50%" y="70px" fill="white" font-size="80px" text-anchor="middle"></text>
<text text-anchor="middle" x="50%" y="70%" fill="white">Logo Here</text>
</svg>
Works totally fine. I am also able to style the polygon's fill with simple CSS. Looks like this:
#hexagon:hover polygon {
fill:#990000;
}
The hover effect fails, however, whenever the mouse leaves the polygon and instead hovers over either of the 'text' elements within the svg. Is there a way to define a CSS rule that prevents this behavior. Or, would it be better (easier) to change the attribute using JS / jQuery?
Thanks!
Your texts are rendered on top of your polygon and are therefore intercepting mouse events. You should set up a css rule like
text {
pointer-events: none;
}
This will prevent the text from becoming a target of mouse events which should give you the desired hover effect for the polygon.
As shown in this fiddle it's possible to render a CSS sprite in SVG using the foreignObject element.
However this isn't supported in IE, so I was wondering if there was another way to do it.
I suspect the answer may be no, because I found two unresolved questions on this (1,2)
I'm using d3.js so any answer that spells out the d3 way to do this would be a bonus.
You could pick out parts of an image using a clipPath if necessary. Extend your jsfiddle like this to see what I mean...
<div class='source youtube'></div>
<svg width="100%" height="100%">
<foreignObject height=50 width=50>
<div class='source facebook'></div>
</foreignObject>
<defs>
<clipPath id="c">
<rect y="10" width="7" height="10"/>
</clipPath>
<clipPath id="c2">
<rect x="7" y="12" width="7" height="10"/>
</clipPath>
</defs>
<image transform="scale(4.5)" y="-5" width="40" height="20" xlink:href="https://s3.amazonaws.com/856/sprite.png" clip-path="url(#c)"/>
<g transform="translate(-30, 0)">
<image transform="scale(4.5)" x="0" y="0" width="40" height="20" xlink:href="https://s3.amazonaws.com/856/sprite.png" clip-path="url(#c2)"/>
</g>
<svg>