I'm kinda new with the whole SVG business, now I'm stumbling upon a problem that I really don't understand.
I'm animating icons at the moment and noticed that repeatedly selecting g's and applying them doesn't work for me. For the sake of the question I've made an example. What I would like it to do is: Load svg > Apply the first 'G' with mask > on click animate the child 'G' upwards > clear > Select a specific 'G' (this time again the first one) > animate it from the bottom to the center
For some reason in stead of grabbing the first 'G' it iterates over the 'G's in the SVG. I've tried this with using Select with Id's, but it's giving me the same troubles.
Sooo what am I doing wrong?
html
<svg id="svg"></svg>
js
var s = Snap("#svg");
s.attr({ viewBox: "0 0 300 300" });
var bigCircle = s.circle(150, 150, 100);
var bigCircle2 = s.circle(150, 150, 100);
bigCircle2.attr({
fill:"none",
stroke: "#0000e6",
strokeWidth: 6
});
bigCircle.attr({
fill: "#fff",
stroke: "#fff",
strokeWidth: 6
});
Snap.load("images/numbers.svg", function (f) {
var apply = function(number){
g = f.select("svg g:nth-child("+number+")");
s.append(g);
g.attr({
mask: bigCircle,
});
p = g.select("g");
};
apply(1); //Please give me the first g in the svg
var g_animate = function(){
p.animate({ transform: 't0,-200' }, 500, mina.easeout, function(){
p.remove();
apply(1); //Let's repeat the first g in the svg
p.attr({transform: 't0,200'});
p.animate({ transform: 't0,0' }, 500, mina.easein)
})
};
$("#svg").click(function(){
g_animate();
});
});
loaded svg
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="300px" height="300px" viewBox="0 0 300 300" enable-background="new 0 0 300 300" xml:space="preserve">
<g>
<g>
<path d="M162.367,212.803v-34.396h-58.358v-11.016l56.04-80.193h18.357v78.068h17.584v13.141h-17.584v34.396H162.367z
M162.367,165.266v-41.932c0-6.57,0.193-13.14,0.58-19.71h-0.58c-3.865,7.343-6.957,12.753-10.436,18.551l-30.724,42.705v0.387
H162.367z"/>
<rect fill="none" width="300" height="300"/>
</g>
</g>
<g>
<g>
<path d="M115.411,193.479c4.83,2.898,15.846,7.73,27.826,7.73c21.642,0,28.599-13.721,28.406-24.35
c-0.193-17.584-16.039-25.119-32.464-25.119h-9.469v-12.754h9.469c12.367,0,28.019-6.377,28.019-21.256
c0-10.049-6.377-18.938-22.029-18.938c-10.048,0-19.71,4.444-25.12,8.309l-4.638-12.367c6.764-4.83,19.517-9.662,33.043-9.662
c24.734,0,35.943,14.687,35.943,29.952c0,13.141-7.924,24.155-23.189,29.759v0.387c15.459,2.898,27.826,14.493,28.02,32.077
c0,20.098-15.846,37.682-45.796,37.682c-14.106,0-26.474-4.443-32.657-8.502L115.411,193.479z"/>
<rect fill="none" width="300" height="300"/>
</g>
</g>
<g>
<g>
<path d="M109.903,213.865v-10.435l13.334-12.947c32.077-30.531,46.764-46.764,46.764-65.7c0-12.754-5.991-24.542-24.735-24.542
c-11.4,0-20.869,5.798-26.666,10.628l-5.411-11.98c8.503-7.149,21.062-12.754,35.362-12.754c27.054,0,38.454,18.551,38.454,36.522
c0,23.188-16.812,41.933-43.285,67.439l-9.854,9.275v0.387h56.231v14.106H109.903z"/>
<rect fill="none" width="300" height="300"/>
</g>
</g>
<g>
<g>
<path d="M154.541,103.043h-0.387l-21.835,11.787l-3.285-12.946l27.439-14.687h14.494v125.605h-16.426V103.043z"/>
<rect fill="none" width="300" height="300"/>
</g>
</g>
</svg>
It won't keep repeating the same g element, as you remove it from the DOM with this...
p.remove();
So next time it selects, it the 2nd initial g will now be the first one.
Edit:
Its also worth looking at what happens with 'append'. If you append an element from a fragment (the data loaded from the file) into the DOM, then that element is no longer in the fragment f. So if you now select a new element, it will be the next g element (as the other one has been removed and added to the DOM). So if you wanted the SAME element, you want to use a css selector on s rather than f.
I'd be tempted to use a selectAll initially on the svg to get all of the g elements into an array and use those to reference them, it may feel more intuitive.
Related
heres my svg file, its just a face as I am practicing
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 720 720" style="enable-background:new 0 0 720 720;" xml:space="preserve">
<g id="skin">
<circle class="skin" cx="364.42" cy="383" r="278"/>
</g>
<g id="mouth">
<path class="mouth" d="M172.92,383c127.67,0,255.33,0,383,0c0,105.05-86.45,191.5-191.5,191.5S172.92,488.05,172.92,383z"/>
</g>
<g id="hair">
<path id = "hair" class = "hair" d="M107.4,276.86c-2.76-50.59,10.76-81.24,24.2-100.13C189.57,95.31,331.92,112,341.92,57.91
c2.04-11.03-2.07-21.46-6.93-29.61c18.47-6.31,81.92-25.39,151.28,3.28c94.59,39.09,121.88,137.21,127.56,160.84
c7.93,32.98,7.18,61.32,5.46,79.42c-38.79-64.73-78.17-85.57-107.42-92.42c-43.32-10.15-60.72,11.26-139.64,11.71
c-67.77,0.39-78.13-15.27-119.49-10.14C216.75,185.45,165.19,204.69,107.4,276.86z"/>
</g>
<g id="eyes">
<g>
<circle class = "eyes" cx="251.17" cy="271.25" r="52.4"/>
<circle class = "eyes" cx="477.67" cy="271.25" r="52.4"/>
</g>
</g>
</svg>
I'm trying to change the hair to blue using a button and an onclick event here:
<button class="blueButton" onclick="hair.style.fill='blue';"></button>
it does not change the color so I was wondering if anyone knew where I was going wrong with this...
Thank you!
You can't just reference the hair element. Instead, call document.getElementById('hair') to get it.
<button class="blueButton" onclick="document.getElementById('hair').style.fill='blue';">Button</button>
Here is a fiddle you can see it work in https://jsfiddle.net/679nLv3p/
You have two SVG objects with the same id hair. Remove the group one.
<g>
<path id = "hair" class = "hair" d="M107.4,276.86c-2.76-50.59,10.76-81.24,24.2-100.13C189.57,95.31,331.92,112,341.92,57.91
c2.04-11.03-2.07-21.46-6.93-29.61c18.47-6.31,81.92-25.39,151.28,3.28c94.59,39.09,121.88,137.21,127.56,160.84
c7.93,32.98,7.18,61.32,5.46,79.42c-38.79-64.73-78.17-85.57-107.42-92.42c-43.32-10.15-60.72,11.26-139.64,11.71
c-67.77,0.39-78.13-15.27-119.49-10.14C216.75,185.45,165.19,204.69,107.4,276.86z"/>
</g>
Working jsbin example
I guessing that I'm trying to do something that just not possible, so this is why I'd like to do :
http://codepen.io/anon/pen/doZpRJ
So I tested multiple way to try to do that, like create a clip shape with a height to 0. But the problem is that I want to make it appear from the bottom.
My first attempt was to create a clip shape and to translate the "SHA" from outside the clip shap to inside.
But this is not working, there is like no "overflow: hidden" effect
Here is my code
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="180px" height="180px" viewBox="0 0 180 180" style="enable-background:new 0 0 180 180;" xml:space="preserve">
<defs>
<clipPath id="clip-shape">
<rect x="10" y="20" width="100" height="50" />
</clipPath>
</defs>
<g>
<path id="sha-shape" style="fill:#FF0000; clip-path: url(#clip-shape);" d="M137.48,44.615c-3.143,0-5.719,2.533-5.719,5.721c0,1.97,1.031,3.658,2.531,4.69l-0.609,1.267
c-0.234,0.469-0.33,0.938-0.33,1.454c0,1.594,1.361,3.235,3.238,3.235c1.219,0,2.344-0.703,2.906-1.829l3.096-6.378
c0.375-0.703,0.607-1.595,0.607-2.438C143.201,47.148,140.576,44.615,137.48,44.615 M123.977,50.666l-1.172-2.486
c-1.08-2.298-3.189-3.611-5.441-3.611c-2.344,0-4.033,1.36-4.922,3.142l-10.693,21.807c-0.422,0.844-0.609,1.829-0.609,2.72
c0,2.908,2.156,5.768,5.486,5.768c2.203,0,4.361-1.36,5.486-3.611L123.977,50.666z M133.59,72.237c0-0.892-0.236-1.829-0.656-2.72
L124.82,52.4l-9.848,19.837h6.613l1.031,2.157c1.078,2.25,3.281,3.611,5.486,3.611c3.328,0,5.439-2.86,5.439-5.768H133.59z
M80.083,72.284V50.29c0-3.142-2.577-5.721-5.72-5.721c-3.143,0-5.674,2.58-5.674,5.721v21.994c0,3.189,2.532,5.721,5.674,5.721
C77.505,78.005,80.083,75.473,80.083,72.284 M98.325,72.284V50.29c0-3.142-2.532-5.721-5.72-5.721c-3.143,0-5.675,2.58-5.675,5.721
v5.673h-5.159V66.61h5.159v5.674c0,3.189,2.532,5.721,5.675,5.721C95.793,78.005,98.325,75.473,98.325,72.284 M53.025,67.782
l-5.909-2.485c-0.468-0.188-0.938-0.33-1.453-0.33c-2.297,0-3.846,2.159-3.846,4.361c0,5.348,6.519,8.583,11.208,8.676V67.782z
M53.025,64.874V44.569c-5.674,0-10.55,4.409-10.55,10.316c0,3.283,1.359,6.19,4.547,7.503L53.025,64.874z M54.714,78.005
c6.283-0.188,11.067-4.455,11.067-10.833c0-7.128-4.737-8.722-11.067-11.067V78.005z M54.714,53.432l4.501,1.688
c0.469,0.141,0.891,0.234,1.407,0.234c2.298,0,3.752-1.688,3.752-3.892c0-4.689-5.816-6.8-9.661-6.894V53.432z"/>
</g>
And my little JS
var shaShape = $('#sha-shape');
TweenLite.set(shaShape, {css: {y: "40px"}});
$('svg').hover(function() {
TweenLite.to(shaShape, .35, {y: "0px"});
}, function() {
TweenLite.to(shaShape, .35, {y: "40px"});
});
You can see the code "working" here :
http://codepen.io/anon/pen/rVYMRm
Cheers,
Just put the clip path on the parent group.
<g style="clip-path: url(#clip-shape);">
<path id="sha-shape" style="fill:#FF0000;" .../>
http://codepen.io/anon/pen/GJONNV
Suppose i have an svg element like so
<svg id="svgCanvas" class="pan" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="none">
<g id="viewport">
//Filled with an arbitrary amount of lines and cirles - examples below.
<line x1="632" y1="357.5" x2="682" y2="270.89745962155615" class="line" style="stroke: rgb(128, 128, 128); stroke-width: 1.3px;"></line>
<circle cx="82.08376766398476" cy="367.0988235405059" r="16.5" stroke="blue" fill="white" class="circle"></circle>
</g>
</svg>
how would i go about clearing everything from the that group, whilst also keeping the group element itself?
Just using DOM methods without the need for any framework you could go for:
var el = document.getElementById("viewport");
while (el.firstChild) {
el.removeChild(el.firstChild);
}
document.addEventListener('load', function(){
document.getElementById("viewport").innerHTML = "";
});
I have the following SVG which works fine on it's own: http://jsfiddle.net/bL3k48jn/1/
However, when imported with fabric.loadSVGFromString the text is no long attached to the path, and the font styles are lost.
The SVG
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="500px" height="500px">
<path id="textPath" fill="none" stroke-width="5" stroke="yellow"
d="
M 250 -250
m 0, 250
a -250,250 0 1,0 0,500
a 250,-250 0 1,0 0,-500
"
/>
<text fill="black" font-family = "arial" text-anchor="middle">
<textPath startOffset="50%" fill="white" stroke="black" stroke-width="2" font-size="36px" font-weight="bold" xlink:href="#textPath">Happy Birthday Dad!</textPath>
</text>
</svg>
You should see a circle with some text following the bottom edge of the curve.
The code I'm using to import the SVG is here: http://jsfiddle.net/hnzgy940/2/
The Javascript
var canvas = new fabric.Canvas('c');
// This is the SVG as a single line
var str = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="500px" height="500px"><path id="text_path" d="M 250 -250 m 0,250 a -250,250 0 1,0 0,500 a 250,-250 0 1,0 0,-500" fill="none" stroke-width="5" stroke="yellow"/><text font-family="arial" text-anchor="middle"><textPath startOffset="50%" fill="white" stroke="black" stroke-width="2" font-size="36px" font-weight="bold" xlink:href="#text_path">Happy Birthday Dad!</textPath></text></svg>';
fabric.loadSVGFromString(str, function(objects, options) {
svg_text = fabric.util.groupSVGElements(objects, options)
svg_text.set({
originX: 'center',
originY: 'center',
left: canvas.width / 2,
top: canvas.height / 2
});
svg_text.setCoords();
canvas.add(svg_text);
canvas.renderAll();
});
It appears to be ignoring the xlink:href attribute, on the <textPath> element, along with the font styles, which I guess means it might just be ignoring the entire <textPath> element, but I can't see why.
I had a problem previously where the text wouldn't show at all, but I think this may have been because I didn't have the correct xmlns attribute.
Text Paths are not supported yet in Fabric, but there is a branch:
https://github.com/lirmont/fabric.js/tree/Curve-Text
Also, see the conversation:
https://github.com/kangax/fabric.js/issues/729
I have created numerous polygon shapes in SVG format. and grouped them together.
When the user hovers over the group a tooltip box appear. I have used ecmascript.
What i am looking to do is make the tooltip box a multiline box.
Any ideas how to do this?
<script type="text/ecmascript">
<![CDATA[
function init(evt)
{
if ( window.svgDocument == null )
{
svgDocument = evt.target.ownerDocument;
}
tooltip = svgDocument.getElementById('tooltip');
tooltip_bg = svgDocument.getElementById('tooltip_bg');
}
function ShowTooltip(evt, mouseovertext)
{
tooltip.setAttributeNS(null,"x",evt.clientX+17);
tooltip.setAttributeNS(null,"y",evt.clientY+14);
tooltip.firstChild.data = mouseovertext;
tooltip.setAttributeNS(null,"visibility","visible");
length = tooltip.getComputedTextLength();
tooltip_bg.setAttributeNS(null,"width",length+8);
tooltip_bg.setAttributeNS(null,"x",evt.clientX+14);
tooltip_bg.setAttributeNS(null,"y",evt.clientY+1);
tooltip_bg.setAttributeNS(null,"visibility","visibile");
}
function HideTooltip(evt)
{
tooltip.setAttributeNS(null,"visibility","hidden");
tooltip_bg.setAttributeNS(null,"visibility","hidden");
}
]]>
</script>
<SVG>
<g onmousemove="ShowTooltip(evt, 'GHANA 2000')" onmouseout="HideTooltip(evt)">
<path fill="#EEEEEE" d="M250,0c47,0,85.183,10.506,125,33.494L250,250V0z"/>
<path id="score" d="M250,57c36.284,0,65.761,8.11,96.5,25.857L250,250V57z"/>
<path fill="none" stroke="#FFFFFF" stroke-width="2" stroke-miterlimit="10" d="M250,0c47,0,85.183,10.506,125,33.494L250,250V0z"/>
<text transform="matrix(1 0 0 1 283.9883 92.0024)" fill="#FFFFFF" font-family="'WalkwayBlack'" font-size="16">62</text>
</g>
<rect class="tooltip_bg" id="tooltip_bg" x="0" y="0" width="55" height="17" visibility="hidden"/>
<text class="tooltip" id="tooltip" x="0" y="0" visibility="hidden">Tooltip</text>
<SVG>
You could create more <text> elements or <tspan> elements within the existing text element, put subsequent lines of text in the additional elements and then position each text/tspan below the previous ones by giving them the same x attribute value and increase the y attribute by the height of the bounding box of the previous line.
Alternatively and more simply, just create <title> elements as children of the polygon shape elements and put the multiline text directly within that and the tooltips will be shown by most UAs as multiline tooltips, it certainly works in Firefox and Opera. Here's a html example but it should work just as well with SVG except that SVG has a title element rather than a title attribute.