I need code to work just like on this page.
Play and pausing of an SVG. I went into inspect and pulled all the code I could, which seemed to be HTML. I could not see or find CSS or Javascript. Not sure if that is normal.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="80 0 1024 768" onload="t=setInterval(updateTimer, 100)">
<script>
var time = 0;
function updateTimer() {
//document.getElementById("t").textContent = document.documentElement.getCurrentTime().toFixed(0) + "s";
}
function pause() {
time = document.documentElement.getCurrentTime();
document.documentElement.pauseAnimations();
clearInterval(t);
}
function play() {
if(time > 0)
document.documentElement.setCurrentTime(time);
clearInterval(t);
t=setInterval(updateTimer, 100);
document.documentElement.unpauseAnimations();
}
function stop() {
time = 0;
clearInterval(t);
document.documentElement.setCurrentTime(0);
document.documentElement.pauseAnimations();
}
</script>
<linearGradient id="grad">
<stop stop-color="rgb(10%,80%,10%)" offset="0"/>
<stop stop-color="rgb(10%,40%,20%)" offset="0.4"/>
<stop stop-color="rgb(10%,90%,30%)" offset="0.7"/>
<stop stop-color="rgb(10%,50%,40%)" offset="1"/>
</linearGradient>
<rect fill="url(#grad)" width="0%" height="50" x="100" y="300" rx="5">
<animate attributeName="width" to="100%" begin="0s" dur="30s"/>
</rect>
<text id="t" style="font:24px Arial Black;fill:white;stroke:black" transform="translate(100 334)"/>
<animateTransform type="translate" attributeName="transform" xlink:href="#t" begin="1s" dur="29s" from="100 334" to="1024 334"/>
<g transform="translate(100 500)">
<!-- Play -->
<g onclick="play()">
<rect width="40" height="40" rx="10" stroke="black" fill-opacity="0.5"/>
<path id="play" d="M12 5l20 15l-20 15Z" fill="white" pointer-events="none"/>
</g>
<!-- Pause -->
<g transform="translate(50 0)">
<rect width="40" height="40" rx="10" stroke="black" fill-opacity="0.5" onclick="pause();"/>
<path id="pause" d="M14 10l0 20M26 10l0 20" stroke="white" fill="none" stroke-width="8" pointer-events="none"/>
</g>
<!-- Stop (rewind and pause) -->
<g transform="translate(100 0)">
<rect width="40" height="40" rx="10" stroke="black" fill-opacity="0.5" onclick="stop()"/>
<rect x="10" y="10" width="20" height="20" fill="white" pointer-events="none"/>
</g>
</g>
</svg>
When I attempt playback on Code pen, the SVG plays but buttons don't work. At all. I thought the "onclick" would do it...?
Is this because the JS isn't accessible/applied? I don't see any "DIV" or "DOM" so I assume its not a CSS thing...
I have a basic knowledge of HTML, less of CSS and know NOTHING about JavaScript
Short version: getCurrentTime & setCurrentTime must be called on the SVG node.
const mySvg = document.getElementById("mySvg")
function updateTimer() {
const t = `${mySvg.getCurrentTime().toFixed(0)}s`;
document.getElementById("t").textContent = t;
}
function setCurrentTime(t) {
mySvg.setCurrentTime(t)
}
function pause() {
mySvg.pauseAnimations()
}
function play() {
mySvg.unpauseAnimations()
}
function stop() {
clearInterval();
setCurrentTime(0);
mySvg.pauseAnimations()
updateTimer();
}
<svg id="mySvg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="80 0 1024 768" onload="t=setInterval(updateTimer, 100)">
<linearGradient id="grad">
<stop stop-color="rgb(10%,80%,10%)" offset="0"/>
<stop stop-color="rgb(10%,40%,20%)" offset="0.4"/>
<stop stop-color="rgb(10%,90%,30%)" offset="0.7"/>
<stop stop-color="rgb(10%,50%,40%)" offset="1"/>
</linearGradient>
<rect fill="url(#grad)" width="0%" height="50" x="100" y="300" rx="5">
<animate attributeName="width" to="100%" begin="0s" dur="30s"/>
</rect>
<text id="t" style="font:24px Arial Black;fill:white;stroke:black" transform="translate(100 334)"/>
<animateTransform type="translate" attributeName="transform" xlink:href="#t" begin="1s" dur="29s" from="100 334" to="1024 334"/>
<g transform="translate(100 500)">
<!-- Play -->
<g onclick="play()">
<rect width="40" height="40" rx="10" stroke="black" fill-opacity="0.5"/>
<path id="play" d="M12 5l20 15l-20 15Z" fill="white" pointer-events="none"/>
</g>
<!-- Pause -->
<g transform="translate(50 0)">
<rect width="40" height="40" rx="10" stroke="black" fill-opacity="0.5" onclick="pause();"/>
<path id="pause" d="M14 10l0 20M26 10l0 20" stroke="white" fill="none" stroke-width="8" pointer-events="none"/>
</g>
<!-- Stop (rewind and pause) -->
<g transform="translate(100 0)">
<rect width="40" height="40" rx="10" stroke="black" fill-opacity="0.5" onclick="stop()"/>
<rect x="10" y="10" width="20" height="20" fill="white" pointer-events="none"/>
</g>
</g>
</svg>
Long version: After all that, why wasn't it working in Codepen?
I can see that the link you posted is to an SVG document with it's own inline JavaScript (in the script tag).
The script calls some SVGElement methods on the SVG root element with document.documentElement.pauseAnimations();.
But what exactly is document element?
Document.documentElement returns the Element that is the root element of the document (for example, the element for HTML documents).
Because this code was called inside an SVG document, document.documentElement returns the SVG root node. However, because codepen is an HTML document, document.documentElement will return the HTML root node.
And you can't call methods like pauseAnimations() on an HTML root node because the HTML root node doesn't understand those methods.
So modern browsers can display SVG documents, HTML documents (and more) but here's the kicker: SVG documents can live inside of HTML documents.
You can see how document.documentElement could refer to two potential things depending on what type of document the JavaScript code was run from.
Trying to move an SVG element using javascript for an interactive game;
<!DOCTYPE html>
<html>
<body>
<svg width="300" height="300">
<circle id="circ" cx="50" cy="50" r="40" fill="black" ></circle>
<animateTransform xlink:href="#circ" attributeName="transform" attributeType="XML" type="translate" from="50 50" to="200 200" dur="1s" repeatCount="1"></animateTransform>
</svg>
</body>
</html>
However, the element drops back to its original position after the animation.
Any suggestions to make the element stay put in the new position?
.
Add fill="freeze" if you want the final animation state to apply after the animation has ended.
<!DOCTYPE html>
<html>
<body>
<svg width="300" height="300">
<circle id="circ" cx="50" cy="50" r="40" fill="black" >
</circle>
<animateTransform xlink:href="#circ" attributeName="transform" attributeType="XML" type="translate" from="50 50" to="200 200" dur="1s" repeatCount="1" fill="freeze"></animateTransform>
</svg>
</body>
</html>
<!DOCTYPE html>
<html>
<body>
<svg width="300" height="300">
<circle id="circ" cx="50" cy="50" r="40" fill="black" >
</circle>
<animateTransform xlink:href="#circ" attributeName="transform" attributeType="XML" type="translate" from="50 50" to="200 200" dur="1s" repeatCount="1" fill="freeze" ></animateTransform>
</svg>
</body>
</html>
You just required to use fill freeze.
I want to color the background of svg text similar to background-color in css
I was only able to find documentation on fill, which colors the text itself
Is it even possible?
You could use a filter to generate the background.
<svg width="100%" height="100%">
<defs>
<filter x="0" y="0" width="1" height="1" id="solid">
<feFlood flood-color="yellow" result="bg" />
<feMerge>
<feMergeNode in="bg"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<text filter="url(#solid)" x="20" y="50" font-size="50">solid background</text>
</svg>
No this is not possible, SVG elements do not have background-... presentation attributes.
To simulate this effect you could draw a rectangle behind the text attribute with fill="green" or something similar (filters). Using JavaScript you could do the following:
var ctx = document.getElementById("the-svg"),
textElm = ctx.getElementById("the-text"),
SVGRect = textElm.getBBox();
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
rect.setAttribute("x", SVGRect.x);
rect.setAttribute("y", SVGRect.y);
rect.setAttribute("width", SVGRect.width);
rect.setAttribute("height", SVGRect.height);
rect.setAttribute("fill", "yellow");
ctx.insertBefore(rect, textElm);
The solution I have used is:
<svg>
<line x1="100" y1="100" x2="500" y2="100" style="stroke:black; stroke-width: 2"/>
<text x="150" y="105" style="stroke:white; stroke-width:0.6em">Hello World!</text>
<text x="150" y="105" style="fill:black">Hello World!</text>
</svg>
A duplicate text item is being placed, with stroke and stroke-width attributes. The stroke should match the background colour, and the stroke-width should be just big enough to create a "splodge" on which to write the actual text.
A bit of a hack and there are potential issues, but works for me!
Instead of using a <text> tag, the <foreignObject> tag can be used, which allows for XHTML content with CSS.
No, you can not add background color to SVG elements. You can do it programmatically with d3.
var text = d3.select("text");
var bbox = text.node().getBBox();
var padding = 2;
var rect = self.svg.insert("rect", "text")
.attr("x", bbox.x - padding)
.attr("y", bbox.y - padding)
.attr("width", bbox.width + (padding*2))
.attr("height", bbox.height + (padding*2))
.style("fill", "red");
Answer by Robert Longson (#RobertLongson) with modifications:
<svg width="100%" height="100%">
<defs>
<filter x="0" y="0" width="1" height="1" id="solid">
<feFlood flood-color="yellow"/>
<feComposite in="SourceGraphic" operator="xor"/>
</filter>
</defs>
<text filter="url(#solid)" x="20" y="50" font-size="50"> solid background </text>
<text x="20" y="50" font-size="50">solid background</text>
</svg>
and we have no bluring and no heavy "getBBox" :)
Padding is provided by white spaces in text-element with filter.
It's worked for me
Going further with #dbarton_uk answer, to avoid duplicating text you can use paint-order=stroke style:
<svg>
<line x1="100" y1="100" x2="350" y2="100" style="stroke:grey; stroke-width: 100"/>
<text x="150" y="105" style="stroke:white; stroke-width:0.5em; fill:black; paint-order:stroke; stroke-linejoin:round">Hello World!</text>
</svg>
Note the stroke-linejoin:round which is needed to avoid seeing spikes for the W sharp angle.
You can combine filter with the text.
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>SVG colored patterns via mask</title>
</head>
<body>
<svg viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter x="0" y="0" width="1" height="1" id="bg-text">
<feFlood flood-color="white"/>
<feComposite in="SourceGraphic" operator="xor" />
</filter>
</defs>
<!-- something has already existed -->
<rect fill="red" x="150" y="20" width="100" height="50" />
<circle cx="50" cy="50" r="50" fill="blue"/>
<!-- Text render here -->
<text filter="url(#bg-text)" fill="black" x="20" y="50" font-size="30">text with color</text>
<text fill="black" x="20" y="50" font-size="30">text with color</text>
</svg>
</body>
</html>
For those wondering how to apply padding to a text element when it has a background like in the Robert's answer, do the following:
<svg>
<defs>
<filter x="-0.1" y="-0.1" width="1.2" height="1.2" id="solid">
<feFlood flood-color="#171717"/>
<feComposite in="SourceGraphic" operator="xor" />
</filter>
</defs>
<text filter="url(#solid)" x="20" y="50" font-size="50">Hello</text>
</svg>
In the example above, filter's x and y positions can be used as transform: translate(-10%, -10%) would, and width and height values can be read as 120% and 120%. So we made background 20% bigger, and offsetted it -10%, so background is now 10% bigger on each side of the text.
this is my favorite hack (not sure it should work). It refer an element that is not yet displayed, and it works pretty well
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 620 40" preserveAspectRatio="xMidYMid meet">
<defs>
<filter x="-0.02" y="0" width="1.04" height="1.1" id="removebackground">
<feFlood flood-color="#00ffff"/>
</filter>
</defs>
<!--Draw the text-->
<use xlink:href="#mygroup" filter="url(#removebackground)" />
<g id="mygroup">
<text id="text1" x="9" y="20" style="text-anchor:start;font-size:14px;">custom text with background</text>
<line x1="200" y1="18" x2="200" y2="36" stroke="#000" stroke-width="5"/>
<line x1="120" y1="27" x2="203" y2="27" stroke="#000" stroke-width="5"/>
</g>
</svg>
The previous answers relied on doubling up text and lacked sufficient whitespace.
By using atop and I was able to get the results I wanted.
This example also includes arrows, a common use case for SVG text labels:
<svg viewBox="-105 -40 210 234">
<title>Size Guide</title>
<defs>
<filter x="0" y="0" width="1" height="1" id="solid">
<feFlood flood-color="white"></feFlood>
<feComposite in="SourceGraphic" operator="atop"></feComposite>
</filter>
<marker id="arrow" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z"></path>
</marker>
</defs>
<g id="garment">
<path id="right-body" fill="none" stroke="black" stroke-width="1" stroke-linejoin="round" d="M0 0 l30 0 l0 154 l-30 0"></path>
<path id="right-sleeve" d="M30 0 l35 0 l0 120 l-35 0" fill="none" stroke-linejoin="round" stroke="black" stroke-width="1"></path>
<use id="left-body" href="#right-body" transform="scale(-1,1)"></use>
<use id="left-sleeve" href="#right-sleeve" transform="scale(-1,1)"></use>
<path id="collar-right-top" fill="none" stroke="black" stroke-width="1" stroke-linejoin="round" d="M0 -6.5 l11.75 0 l6.5 6.5"></path>
<use id="collar-left-top" href="#collar-right-top" transform="scale(-1,1)"></use>
<path id="collar-left" fill="white" stroke="black" stroke-width="1" stroke-linejoin="round" d="M-11.75 -6.5 l-6.5 6.5 l30 77 l6.5 -6.5 Z"></path>
<path id="front-right" fill="white" stroke="black" stroke-width="1" d="M18.25 0 L30 0 l0 154 l-41.75 0 l0 -77 Z"></path>
<line x1="0" y1="0" x2="0" y2="154" stroke="black" stroke-width="1" stroke-dasharray="1 3"></line>
<use id="collar-right" href="#collar-left" transform="scale(-1,1)"></use>
</g>
<g id="dimension-labels">
<g id="dimension-sleeve-length">
<line marker-start="url(#arrow)" marker-end="url(#arrow)" x1="85" y1="0" x2="85" y2="120" stroke="black" stroke-width="1"></line>
<text font-size="10" filter="url(#solid)" fill="black" x="85" y="60" class="dimension" text-anchor="middle" dominant-baseline="middle"> 120 cm</text>
</g>
<g id="dimension-length">
<line marker-start="url(#arrow)" marker-end="url(#arrow)" x1="-85" y1="0" x2="-85" y2="154" stroke="black" stroke-width="1"></line>
<text font-size="10" filter="url(#solid)" fill="black" x="-85" y="77" text-anchor="middle" dominant-baseline="middle" class="dimension"> 154 cm</text>
</g>
<g id="dimension-sleeve-to-sleeve">
<line marker-start="url(#arrow)" marker-end="url(#arrow)" x1="-65" y1="-20" x2="65" y2="-20" stroke="black" stroke-width="1"></line>
<text font-size="10" filter="url(#solid)" fill="black" x="0" y="-20" text-anchor="middle" dominant-baseline="middle" class="dimension"> 130 cm </text>
</g>
<g title="Back Width" id="dimension-back-width">
<line marker-start="url(#arrow)" marker-end="url(#arrow)" x1="-30" y1="174" x2="30" y2="174" stroke="black" stroke-width="1"></line>
<text font-size="10" filter="url(#solid)" fill="black" x="0" y="174" text-anchor="middle" dominant-baseline="middle" class="dimension"> 60 cm </text>
</g>
</g>
</svg>
An obvious workaround to the problem of the blur produced by the filter effect is to render the <text> two times: once for the background (with transparent characters) and once for the characters (without a background filter).
For me, this was the only way to make the text readable in Safari.
<svg width="100%" height="100%">
<filter x="0" y="0" width="1" height="1" id="solid">
<feFlood flood-color="yellow" />
</filter>
<g transform="translate(20, 50)" font-size="50">
<text aria-hidden="true" fill="none" filter="url(#solid)">solid background</text>
<text fill="blue">solid background</text>
</g>
</svg>
The aria-hidden="true" attribute is there to prevent screen readers from speaking the text twice, if the user uses a screen reader.
You can add style to your text:
style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
text-shadow: rgb(255, 255, 255) -2px -2px 0px, rgb(255, 255, 255) -2px 2px 0px,
rgb(255, 255, 255) 2px -2px 0px, rgb(255, 255, 255) 2px 2px 0px;"
White, in this example.
Does not work in IE :)
For example i have this in html
<svg id="svg-img1" width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
<line x1="0" y1="0" x2="0" y2="0" style="stroke:black; stroke-width:1px;"></line>
<line x1="0" y1="0" x2="0" y2="0" style="stroke:black; stroke-width:1px;"></line>
<line x1="0" y1="0" x2="0" y2="0" style="stroke:black; stroke-width:1px;"></line>
<line x1="0" y1="0" x2="0" y2="0" style="stroke:black; stroke-width:1px;"> </line>
</svg>
and this in my js
$('svg').find('line').each(function(){
$(this).attr('style','stroke:red');
sleep(10);
});
and "sleep" function
function sleep(ms) {
ms += new Date().getTime();
while (new Date() < ms){}
}
When executing, the color of my lines changes at once for everyone. And I need the color of the lines to change in turn, and so that it can be seen as one color after another changes color. Something similar to animation
Tried without jquery - the same result
Use the SVG animate element:
<animate id="a14" attributeName="stroke" from="black" to="red"
dur="3s" begin="9s;al4.end+3s" stroke="freeze" />
NOTE: Do not cut and paste the code above, it has been broken in the middle so that it can be seen without scrolling.
attributeName: The name of the attribute to animate
from: Starting value
to: Ending value
dur: Duration of animation
begin: When to begin; this particular set of values says: start in 9 seconds; (referenced this animate element by id) to end in 3 seconds
stroke: The attribute that's being animated, this attribute will stop after it has animated,
SNIPPET
<svg id="svg-img1" width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
<line x1="0" y1="10" x2="400" y2="10" style="stroke:black; stroke-width:1px;">
<animate id="a11" attributeName="stroke" from="black" to="red" dur="3s" begin="0s;al1.end+3s" stroke="freeze" />
</line>
<line x1="0" y1="20" x2="400" y2="20" style="stroke:black; stroke-width:1px;">
<animate id="a12" attributeName="stroke" from="=black" to="red" dur="3s" begin="3s;al2.end+3s" stroke="freeze" />
</line>
<line x1="0" y1="30" x2="400" y2="30" style="stroke:black; stroke-width:1px;">
<animate id="a13" attributeName="stroke" from="black" to="red" dur="3s" begin="6s;al3.end+3s" stroke="freeze" />
</line>
<line x1="0" y1="40" x2="400" y2="40" style="stroke:black; stroke-width:1px;">
<animate id="a14" attributeName="stroke" from="black" to="red" dur="3s" begin="9s;al4.end+3s" stroke="freeze" />
</line>
</svg>
Instead of sleep, you can use window.setTimeout to execute a function after a certain delay. So, you could do something like this:
$('svg').find('line').each(function(index, element){
window.setTimeout(function() {
$(element).attr('style','stroke:red');
}, index * 100);
});
I created a SVG file contains 5 polygons, then I need to embed Javascript so 4 of the polygons' color changes to Red when mouseover, and when mouseout, the color changes to Green. I tried to write the code but it didn't work, what could be the problem? Thanks for help and tips!
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="26cm" height="24cm" viewBox="0 0 2600 2400" version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink= "http://www.w3.org/1999/xlink">
<script type="text/javascript">
<![CDATA[
document.getElementById("test").onmouseover = function(){changeColor()};
function changeColor() {
document.getElementById("test").style.color = "red";
}
document.getElementById("test").onmouseout = function(){changeColor()};
function changeColor() {
document.getElementById("test").style.color = "green";
}
]]>
</script>
<circle cx="1600" cy="700" r="600" fill="yellow" stroke="black" stroke-width="3"/>
<ellipse id="test" cx="1300" cy="500" rx="74" ry="120" fill="blue" stroke="black" stroke-width="3" onmouseover="javascript:red();" onmouseout="javascript:green();"/>
<ellipse id="test" cx="1850" cy="500" rx="74" ry="120" fill="blue" stroke="black" stroke-width="3" onmouseover="javascript:red();" onmouseout="javascript:green();"/>
<rect id="test" x="1510" y="650" width="160" height="160" fill="blue" stroke="black" stroke-width="3" onmouseover="javascript:red();" onmouseout="javascript:green();"/>
<polygon id="test" points="1320,800 1370,1080 1820,1080 1870,800 1820,1000 1370,1000" name="mouth" fill="blue" stroke="black" stroke-width="3" onmouseover="javascript:red();" onmouseout="javascript:green();"/>
</svg>
For what you are doing I would recommend using pure CSS.
Here is some working code.
svg:hover .recolor {
fill: red;
}
As you see, you can just use the :hover event in CSS to recolor the necessary elements. And set them to your default color (green), which will take effect when the user is not hovered.
You have various errors
you've two functions called changeColor, functions must have unique names
SVG does not use color to colour elements, instead it uses fill (and stroke).
id values must be unique, you probably want to replace id by class and then use getElementsByClassName instead of getElementById. If you do that you'll need to cope with more than one element though. I've not completed that part, you should try it yourself so you understand what's going on.
I've removed all but one id from my version so you can see it working on the left eye.
document.getElementById("test").onmouseover = function(){changeColor()};
function changeColor() {
document.getElementById("test").style.fill = "red";
}
document.getElementById("test").onmouseout = function(){changeColor2()};
function changeColor2() {
document.getElementById("test").style.fill = "green";
}
<svg width="26cm" height="24cm" viewBox="0 0 2600 2400" version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink= "http://www.w3.org/1999/xlink">
<circle cx="1600" cy="700" r="600" fill="yellow" stroke="black" stroke-width="3"/>
<ellipse id="test" cx="1300" cy="500" rx="74" ry="120" fill="blue" stroke="black" stroke-width="3"/>
<ellipse cx="1850" cy="500" rx="74" ry="120" fill="blue" stroke="black" stroke-width="3" />
<rect x="1510" y="650" width="160" height="160" fill="blue" stroke="black" stroke-width="3" />
<polygon points="1320,800 1370,1080 1820,1080 1870,800 1820,1000 1370,1000" name="mouth" fill="blue" stroke="black" stroke-width="3"/>
</svg>