I have the following code which seems like it should display a <paper-tooltip> when the chart is hovered over, but it does not. Hovering causes the <paper-tooltip> node in the DOM to update, but it doesn't show up. What am I doing wrong?
<svg id="svg_fbff5dd2-1724-4f3d-a0b2-2fbe41d75e89" width="600" height="450">
<g>
<line opacity="1" x1="167.0000000000005" y1="225.00001160643953" x2="121.49166679382381" y2="220.40001302639112" style="stroke: #A9A9A9; stroke-width: 1"></line>
<g>
<defs>
<radialGradient id="radialGradient_0_fbff5dd2-1724-4f3d-a0b2-2fbe41d75e89" cx="50%" cy="50%" fx="50%" fy="50%" r="50%" gradientUnits="userSpaceOnUse">
<stop offset="40%" stop-color="#DBDBDB"></stop>
<stop offset="100%" stop-color="#777777"></stop>
</radialGradient>
</defs>
<path id="pieWedge_0_fbff5dd2-1724-4f3d-a0b2-2fbe41d75e89" class="pie-chart-wedge" fill="url(#radialGradient_0_fbff5dd2-1724-4f3d-a0b2-2fbe41d75e89)" d="M300,225 L435,225 A135,135 0 1 1 434.99999999999795,224.99997643805509z"></path>
<paper-tooltip position="right" animation-delay="0.5" fittovisiblebounds="true" role="tooltip" tabindex="-1" class="x-scope paper-tooltip-0" style="left: 279.15px; top: 1841.22px;">
<div id="tooltip" class="style-scope paper-tooltip" hidden="">
Austin Office: 100.0
</div>
</paper-tooltip>
<rect opacity="1" fill="white" style="stroke: #A9A9A9; stroke-width: 1" x="92.98333358764705" y="213.5000129310237" width="57.016666412353516" height="13.800000190734863"></rect>
<text class="pie-label-fbff5dd2-1724-4f3d-a0b2-2fbe41d75e89" opacity="1" x="94.98333358764705" y="225.0000130899694" font-size="11" textLength="53.016666412353516" lengthAdjust="spacingAndGlyphs">Austin Office</text>
</g>
<circle cx="300" cy="225" r="54" fill="white"></circle>
</g>
</svg>
I'm adding the tooltip using:
var paperTT = document.createElement("paper-tooltip");
paperTT.setAttribute("position", "right");
paperTT.setAttribute("animation-delay", "0.5");
paperTT.setAttribute("fitToVisibleBounds", "true");
paperTT.textContent = this.name + ": " + (this.fraction * 100).toFixed(1);
group.appendChild(paperTT);
The <paper-tooltip> should be outside the <svg>, and set <paper-tooltip>.for to the element ID of the hover target (presumably the pie wedge).
<paper-tooltip for="pieWedge">
Austin Office: 100.0
</paper-tooltip>
<svg>
...
<path id="pieWedge">...</path>
</svg>
HTMLImports.whenReady(() => {
Polymer({
is: 'x-foo'
});
});
<head>
<base href="https://polygit.org/polymer+1.7.1/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
<link rel="import" href="paper-tooltip/paper-tooltip.html">
</head>
<body>
<x-foo></x-foo>
<dom-module id="x-foo">
<template>
<paper-tooltip for="pieWedge"
position="right"
animation-delay="0.5"
fittovisiblebounds
tabindex="-1"
style="left: 279.15px; top: 1841.22px;">
Austin Office: 100.0
</paper-tooltip>
<svg id="svg" width="600" height="450">
<g>
<line opacity="1" x1="167.0000000000005" y1="225.00001160643953" x2="121.49166679382381" y2="220.40001302639112"
style="stroke: #A9A9A9; stroke-width: 1"></line>
<g>
<defs>
<radialGradient id="radialGradient_0_fbff5dd2-1724-4f3d-a0b2-2fbe41d75e89" cx="50%" cy="50%" fx="50%"
fy="50%" r="50%" gradientUnits="userSpaceOnUse">
<stop offset="40%" stop-color="#DBDBDB"></stop>
<stop offset="100%" stop-color="#777777"></stop>
</radialGradient>
</defs>
<path id="pieWedge" class="pie-chart-wedge"
fill="url(#radialGradient_0_fbff5dd2-1724-4f3d-a0b2-2fbe41d75e89)"
d="M300,225 L435,225 A135,135 0 1 1 434.99999999999795,224.99997643805509z"></path>
<rect opacity="1" fill="white" style="stroke: #A9A9A9; stroke-width: 1" x="92.98333358764705"
y="213.5000129310237" width="57.016666412353516" height="13.800000190734863"></rect>
<text class="pie-label-fbff5dd2-1724-4f3d-a0b2-2fbe41d75e89" opacity="1" x="94.98333358764705"
y="225.0000130899694" font-size="11" textLength="53.016666412353516" lengthAdjust="spacingAndGlyphs">
Austin Office
</text>
</g>
<circle cx="300" cy="225" r="54" fill="white"></circle>
</g>
</svg>
</template>
</dom-module>
</body>
codepen
Related
Is it possible to get a shadow effect only on the outside border?
image
Directly from the docs: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feDropShadow#SVG
<svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="shadow">
<feDropShadow dx="0.2" dy="0.4" stdDeviation="0.2"/>
</filter>
<filter id="shadow2">
<feDropShadow dx="0" dy="0" stdDeviation="0.5"
flood-color="cyan"/>
</filter>
<filter id="shadow3">
<feDropShadow dx="-0.8" dy="-0.8" stdDeviation="0"
flood-color="pink" flood-opacity="0.5"/>
</filter>
</defs>
<circle cx="5" cy="50%" r="4"
style="fill:pink; filter:url(#shadow);"/>
<circle cx="15" cy="50%" r="4"
style="fill:pink; filter:url(#shadow2);"/>
<circle cx="25" cy="50%" r="4"
style="fill:pink; filter:url(#shadow3);"/>
</svg>
Output (middle one should be what you need? Just need to change to a path - I will try to do that now):
With Path:
<svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="shadow">
<feDropShadow dx="0.2" dy="0.4" stdDeviation="0.2"/>
</filter>
<filter id="shadow2">
<feDropShadow dx="0" dy="0" stdDeviation="0.5"
flood-color="cyan"/>
</filter>
<filter id="shadow3">
<feDropShadow dx="-0.8" dy="-0.8" stdDeviation="0"
flood-color="pink" flood-opacity="0.5"/>
</filter>
</defs>
<circle cx="5" cy="50%" r="4"
style="fill:pink; filter:url(#shadow);"/>
<path d="M11 1, v8, h8, v-8, z"
style="fill:white; filter:url(#shadow2);"/>
<circle cx="25" cy="50%" r="4"
style="fill:pink; filter:url(#shadow3);"/>
Output:
Now I see some issues, as it's not transparent:
<svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="shadow">
<feDropShadow dx="0.2" dy="0.4" stdDeviation="0.2"/>
</filter>
<filter id="shadow2">
<feDropShadow dx="0" dy="0" stdDeviation="0.5"
flood-color="cyan" flood-opacity="0.5"/>
</filter>
<filter id="shadow3">
<feDropShadow dx="-0.8" dy="-0.8" stdDeviation="0"
flood-color="pink" flood-opacity="0.7"/>
</filter>
</defs>
<circle cx="5" cy="50%" r="4"
style="fill:pink; filter:url(#shadow);"/>
<circle cx="25" cy="50%" r="4"
style="fill:pink; filter:url(#shadow3);"/>
<mask id="myMask">
<!-- Everything under a white pixel will be visible -->
<rect x="0" y="0" width="100%" height="100%" fill="white" />
<!-- Everything under a black pixel will be invisible -->
<polygon fill="black" points="0.02,0.02 0.98,0.02 0.98,0.98 0.02,0.98 0.02,0.02" />
<!--
<path d="M14 1, v8, h8, v-8, z" fill="black" />
-->
</mask>
<rect x="16" y="1" width="8" height="8"
mask="url(#myMask)"
fill="white"
stroke="black"
stroke-width="0.2"
style="filter:url(#shadow2);"/>
<!--
<path d="M14 1, v8, h8, v-8, z"
style="fill:white; stroke:black; stroke-width: 0.2;
mask=url(#myMask);
filter:url(#shadow2);"/>
-->
<!--
<path d="M14 1, v8, h8, v-8, z"
style="fill:none; stroke:black; stroke-width: 0.2;
clip-path: polygon(0% 0%, 0% 100%, 1% 100%, 1% 1%, 99% 1%, 99% 99%, 1% 99%, 1% 100%, 100% 100%, 100% 0%);
filter:url(#shadow2);"/>
<rect x="14" y="1" width="8" height="8"
style="fill:white; stroke:black; stroke-width: 0.2;
clip-path: polygon(0% 0%, 0% 100%, 1% 100%, 1% 1%, 99% 1%, 99% 99%, 1% 99%, 1% 100%, 100% 100%, 100% 0%);
filter:url(#shadow2);"/>
-->
Output (not yet transparent):
Next try:
I can do it with a rect or a path (the circle is behind the rect/path and you see through) but I don't (yet) know how to do it for an arbitrary path:
<svg viewBox="0 0 200 100" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="shadow2">
<feDropShadow dx="0" dy="0" stdDeviation="2"
flood-color="cyan" flood-opacity="0.7"/>
</filter>
</defs>
<mask id="myMask" maskContentUnits="objectBoundingBox">
<rect fill="white" x="-10%" y="-10%" width="120%" height="120%" />
<polygon fill="black" points="0.02,0.02 0.98,0.02 0.98,0.98 0.02,0.98 0.02,0.02" />
</mask>
<!--
Punch a hole in a shape of a square inside the white rect,
revealing the yellow circle underneath
-->
<circle cx="50" cy="50" r="20" fill="yellow" />
<!--
<rect x="25" y="25" height="50" width="50" fill="white"
stroke="black"
stroke-width="2"
mask="url(#myMask)"
style="filter:url(#shadow2);"
/>
-->
<path d="M25,25 v50, h50, v-50, z" fill="white"
stroke="black"
stroke-width="2"
mask="url(#myMask)"
style="filter:url(#shadow2);"
/>
</svg>
Output:
Another example:
<svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="shadow">
<feDropShadow dx="0.2" dy="0.4" stdDeviation="0.2" />
</filter>
<filter id="shadow2">
<feDropShadow dx="0" dy="0" stdDeviation="0.8" flood-color="cyan" flood-opacity="0.7" />
</filter>
<filter id="shadow3">
<feDropShadow dx="-0.8" dy="-0.8" stdDeviation="0" flood-color="pink" flood-opacity="0.7" />
</filter>
</defs>
<mask id="myMask" maskContentUnits="objectBoundingBox">
<rect fill="white" x="-10%" y="-10%" width="120%" height="120%" />
<polygon fill="black" points="0.015,0.015 0.985,0.015 0.985,0.985 0.015,0.985 0.015,0.015" />
</mask>
<!--
Punch a hole in a shape of a square inside the white rect,
revealing the yellow circle underneath
-->
<circle cx="5" cy="50%" r="4" style="fill:pink; filter:url(#shadow);" />
<circle cx="25" cy="50%" r="4" style="fill:pink; filter:url(#shadow3);" />
<path d="M14 1, v8, h8, v-8, z" fill="white" stroke="black" stroke-width="0.2" mask="url(#myMask)" style="filter:url(#shadow2);" />
<!-- <rect x="14" y="1" height="8" width="8" fill="white" stroke="black" stroke-width="0.2" mask="url(#myMask)" style="filter:url(#shadow2);" /> -->
<!-- <circle cx="50" cy="50" r="20" fill="yellow" /> -->
<!-- <rect x="25" y="25" height="50" width="50" fill="white" stroke="black" stroke-width="2" mask="url(#myMask)" style="filter:url(#shadow2);" /> -->
</svg>
Output:
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.
I am trying to center a group that has a d3 tree inside of it. The svg is currently positioned perfectly across the browser and I am just trying to get the dynamically loaded tree to stay in the center of that svg element. All tree elements are within one group and have a zoom listener and have the ability to pan.
<svg width="1535" height="685" overflow-y="hidden" class="overlay">
<g transform="translate(742.5,342.5)scale(1)">
<g class="node" transform="translate(0,25)">
<circle class="nodeCircle" r="4.5" style="fill: rgb(255, 255, 255)</circle>
<text x="10" dy=".35em" class="nodeText" text-anchor="start" style="fill-opacity: 1;"></text>
<text x="10" dy="1.5em" class="nodeText" text-anchor="start"></text>
</g>
</g>
</svg>
i hope you understand the concept
first you draw svg with width: 1535 and hight :685
you want to make g element on middle of it
middle of it means half of width(1535/2) and half of height (685/2)
w:767.5 h:342.5
you draw g and transform it. good point but you must set transform to right place, that means on middle of svg to 742.5 and 342.5
so that means you need transform x,y) it more (25,0)
why you set it wrong
<g class="node" transform="translate(0,25)">
it must be
<g class="node" transform="translate(25,0)">
this is little example
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.3/d3.min.js"></script>
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg{
border-style: solid;
border-color: red;
}
}
</style>
<script src="https://d3js.org/d3.v4.min.js"></script>
<body>
<svg width="200" height="100" overflow-y="hidden" class="overlay">
<g transform="translate(70,20)scale(1)">
<g class="node" transform="translate(30,30)">
<circle class="nodeCircle" r="10" style="fill: black"</circle>
<text x="10" dy=".35em" class="nodeText" text-anchor="start" style="fill-opacity: 1;"></text>
<text x="10" dy="1.5em" class="nodeText" text-anchor="start"></text>
</g>
</g>
</svg>
<svg width="200" height="100" overflow-y="hidden" class="overlay">
<g transform="translate(100,50)scale(1)">
<g class="node" transform="translate(0,0)">
<circle class="nodeCircle" r="10" style="fill: black"</circle>
<text x="10" dy=".35em" class="nodeText" text-anchor="start" style="fill-opacity: 1;"></text>
<text x="10" dy="1.5em" class="nodeText" text-anchor="start"></text>
</g>
</g>
</svg>
<br/>
<svg width="200" height="100" overflow-y="hidden" class="overlay">
<g transform="translate(200,50)scale(1)">
<g class="node" transform="translate(0,0)">
<circle class="nodeCircle" r="10" style="fill: black"</circle>
<text x="10" dy=".35em" class="nodeText" text-anchor="start" style="fill-opacity: 1;"></text>
<text x="10" dy="1.5em" class="nodeText" text-anchor="start"></text>
</g>
</g>
</svg>
<svg width="200" height="100" overflow-y="hidden" class="overlay">
<g transform="translate(100,10)scale(1)">
<g class="node" transform="translate(100,40)">
<circle class="nodeCircle" r="10" style="fill: black"</circle>
<text x="10" dy=".35em" class="nodeText" text-anchor="start" style="fill-opacity: 1;"></text>
<text x="10" dy="1.5em" class="nodeText" text-anchor="start"></text>
</g>
</g>
</svg>
</body>
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 :)
I am making an app and I want to have a responsive SVG progress bar.
My code is below, but the progress bar is not responsive. How can I achieve responsiveness?
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<svg version="1.1" height="200" width="850" y="0" x="0">
<g>
<defs>
<linearGradient spreadMethod="reflect" y2="0%" x2="100%" y1="0%" x1="0%" id="myLinearGradient3">
<stop stop-opacity="1" stop-color="#D7565A" offset="10%"/>
<stop stop-opacity="1" stop-color="#E58E5F" offset="25%"/>
<stop stop-opacity="1" stop-color="#E58E5F" offset="26%"/>
<stop stop-opacity="1" stop-color="#EAEAEA" offset="57%"/>
<stop stop-opacity="1" stop-color="#FFF34D" offset="58%"/>
<stop stop-opacity="1" stop-color="#EAEAEA" offset="77%"/>
<stop stop-opacity="1" stop-color="#4dd4ff" offset="78%"/>
</linearGradient>
</defs>
<!-- Gradient table -->
<rect style="fill:url(#myLinearGradient3); stroke: #8D99A6; stroke-width: 0.5;" ry="10" rx="10" height="20" width="800" y="100" x="25"/>
</g>
<!-- Ruler -->
<!-- ballons -->
<g>
<text text-anchor="start" font-size="11" font-weight="bold" font-family="Gotham-Book" stroke-width="1" fill="#000000" y="137" x="45">(++)</text>
<text text-anchor="start" font-size="11" font-weight="bold" font-family="Gotham-Book" stroke-width="1" fill="#000000" y="137" x="795">(--)</text>
<text text-anchor="start" font-size="10" font-weight="normal" font-family="Gotham-Book" stroke-width="1" fill="#8B97A3" y="95" x="40">DEFICIENT</text>
<text text-anchor="start" font-size="10" font-weight="normal" font-family="Gotham-Book" stroke-width="1" fill="#8B97A3" y="95" x="255">SUB-NORMAL</text>
<text text-anchor="start" font-size="10" font-weight="normal" font-family="Gotham-Book" stroke-width="1" fill="#8B97A3" y="95" x="445">NORMAL</text>
<!-- movable vertical lines : user exact value with ballon -->
<!-- line 1 -->
</g>
</svg>
</body>
</html>
You would use a viewBox to create responsive SVG. I've made the height and width 100% too.
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<svg height="100%" width="100%" viewBox="0 0 1000 4000" preserveAspectRatio="none">
<g>
<defs>
<linearGradient spreadMethod="reflect" y2="0%" x2="100%" y1="0%" x1="0%" id="myLinearGradient3">
<stop stop-opacity="1" stop-color="#D7565A" offset="10%"/>
<stop stop-opacity="1" stop-color="#E58E5F" offset="25%"/>
<stop stop-opacity="1" stop-color="#E58E5F" offset="26%"/>
<stop stop-opacity="1" stop-color="#EAEAEA" offset="57%"/>
<stop stop-opacity="1" stop-color="#FFF34D" offset="58%"/>
<stop stop-opacity="1" stop-color="#EAEAEA" offset="77%"/>
<stop stop-opacity="1" stop-color="#4dd4ff" offset="78%"/>
</linearGradient>
</defs>
<!-- Gradient table -->
<rect style="fill:url(#myLinearGradient3); stroke: #8D99A6; stroke-width: 0.5;" ry="10" rx="10" height="20" width="800" y="100" x="25"/>
</g>
<!-- Ruler -->
<!-- ballons -->
<g>
<text text-anchor="start" font-size="11" font-weight="bold" font-family="Gotham-Book" stroke-width="1" fill="#000000" y="137" x="45">(++)</text>
<text text-anchor="start" font-size="11" font-weight="bold" font-family="Gotham-Book" stroke-width="1" fill="#000000" y="137" x="795">(--)</text>
<text text-anchor="start" font-size="10" font-weight="normal" font-family="Gotham-Book" stroke-width="1" fill="#8B97A3" y="95" x="40">DEFICIENT</text>
<text text-anchor="start" font-size="10" font-weight="normal" font-family="Gotham-Book" stroke-width="1" fill="#8B97A3" y="95" x="255">SUB-NORMAL</text>
<text text-anchor="start" font-size="10" font-weight="normal" font-family="Gotham-Book" stroke-width="1" fill="#8B97A3" y="95" x="445">NORMAL</text>
<!-- movable vertical lines : user exact value with ballon -->
<!-- line 1 -->
</g>
</svg>
</body>
</html>
Here is what i did :
Removed the svg's width and height
Added a viewbox - read here
Gave the SVG an absolute position and wrap it inside a container - See here for more examples
svg {
position: absolute;
top: 0;
left: 0;
}
.container {
width: 100%;
height: 0;
padding-top: 50%;
position: relative;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div class="container">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" y="0" x="0" viewBox="0 0 850 200">
<g>
<defs>
<linearGradient spreadMethod="reflect" y2="0%" x2="100%" y1="0%" x1="0%" id="myLinearGradient3">
<stop stop-opacity="1" stop-color="#D7565A" offset="10%"/>
<stop stop-opacity="1" stop-color="#E58E5F" offset="25%"/>
<stop stop-opacity="1" stop-color="#E58E5F" offset="26%"/>
<stop stop-opacity="1" stop-color="#EAEAEA" offset="57%"/>
<stop stop-opacity="1" stop-color="#FFF34D" offset="58%"/>
<stop stop-opacity="1" stop-color="#EAEAEA" offset="77%"/>
<stop stop-opacity="1" stop-color="#4dd4ff" offset="78%"/>
</linearGradient>
</defs>
<!-- Gradient table -->
<rect style="fill:url(#myLinearGradient3); stroke: #8D99A6; stroke-width: 0.5;" ry="10" rx="10" height="20" width="800" y="100" x="25" />
</g>
<!-- Ruler -->
<!-- ballons -->
<g>
<text text-anchor="start" font-size="11" font-weight="bold" font-family="Gotham-Book" stroke-width="1" fill="#000000" y="137" x="45">(++)</text>
<text text-anchor="start" font-size="11" font-weight="bold" font-family="Gotham-Book" stroke-width="1" fill="#000000" y="137" x="795">(--)</text>
<text text-anchor="start" font-size="10" font-weight="normal" font-family="Gotham-Book" stroke-width="1" fill="#8B97A3" y="95" x="40">DEFICIENT</text>
<text text-anchor="start" font-size="10" font-weight="normal" font-family="Gotham-Book" stroke-width="1" fill="#8B97A3" y="95" x="255">SUB-NORMAL</text>
<text text-anchor="start" font-size="10" font-weight="normal" font-family="Gotham-Book" stroke-width="1" fill="#8B97A3" y="95" x="445">NORMAL</text>
<!-- movable vertical lines : user exact value with ballon -->
<!-- line 1 -->
</g>
</svg>
</div>
</body>
</html>
All html5 elements are quite responsive, you just need to change all width and Xcoordinate - from PX values into %
<svg version="1.1" height="200" width="100%" y="0" x="0">
<g>
<defs>
<linearGradient spreadMethod="reflect" y2="0%" x2="100%" y1="0%" x1="0%" id="myLinearGradient3">
<stop stop-opacity="1" stop-color="#D7565A" offset="10%"/>
<stop stop-opacity="1" stop-color="#E58E5F" offset="25%"/>
<stop stop-opacity="1" stop-color="#E58E5F" offset="26%"/>
<stop stop-opacity="1" stop-color="#EAEAEA" offset="57%"/>
<stop stop-opacity="1" stop-color="#FFF34D" offset="58%"/>
<stop stop-opacity="1" stop-color="#EAEAEA" offset="77%"/>
<stop stop-opacity="1" stop-color="#4dd4ff" offset="78%"/>
</linearGradient>
</defs>
<!-- Gradient table -->
<rect style="fill:url(#myLinearGradient3); stroke: #8D99A6; stroke-width: 0.5;" ry="10" rx="10" height="20" width="94%" y="100" x="5%"/>
</g>
<!-- Ruler -->
<!-- ballons -->
<g>
<text text-anchor="start" font-size="11" font-weight="bold" font-family="Gotham-Book" stroke-width="1" fill="#000000" y="137" x="5.6%">(++)</text>
<text text-anchor="start" font-size="11" font-weight="bold" font-family="Gotham-Book" stroke-width="1" fill="#000000" y="137" x="94%">(--)</text>
<text text-anchor="start" font-size="10" font-weight="normal" font-family="Gotham-Book" stroke-width="1" fill="#8B97A3" y="95" x="5%">DEFICIENT</text>
<text text-anchor="start" font-size="10" font-weight="normal" font-family="Gotham-Book" stroke-width="1" fill="#8B97A3" y="95" x="31.87%">SUB-NORMAL</text>
<text text-anchor="start" font-size="10" font-weight="normal" font-family="Gotham-Book" stroke-width="1" fill="#8B97A3" y="95" x="55.62%">NORMAL</text>
<!-- movable vertical lines : user exact value with ballon -->
<!-- line 1 -->
</g>
</svg>
DEMO
Cheers,
Ashok