Add image to svg circle using D3 - d3.js

I'm trying to add a background image to a svg circle. Below I show both versions but I commented out the part that works. I'm trying to use D3 to create the same elements on the page. When checking the console the circle svg shows up but no image.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg {
stroke: 1;
}
</style>
<body>
<script type="text/javascript" src="d3.min.js"></script>
<!--
<svg height="500" width="800">
<defs>
<pattern id="apple" height="100%" width="100%"
patternContentUnits="objectBoundingBox">
<image height="1" width="1" preserveAspectRation="none"
xlink:href="apple.jpeg"></image>
</pattern>
</defs>
<circle cx="50" cy="50" r="40" fill="url(#apple)" />
</svg>
-->
<script>
// now trying to add same image inside a circle using D3
var svg = d3.select("body")
.append("svg")
.attr("height",500)
.attr("width",800);
var defs = svg.append("defs")
.append("pattern")
.attr("id", "apple")
.attr("height","100%")
.attr("width", "100%")
.attr("patternContenUnits", "objectBoundingBox")
.append("image")
.attr("height",1)
.attr("width",1)
.attr("preserveAspectRatio","none")
.attr("xlink:href","apple.jpeg");
var circle = svg.append("circle")
.attr("cx",50)
.attr("cy",50)
.attr("r",40)
.attr("fill","url(#apple)");
</script>
</body>
</html>

Related

Why my image positioning in svg has an offset of 22?

I try to position an image inside a svg graphics to the left border, but with x=0 the image has a offset of 22. When x=-22 it fits, but why?
This is my svg:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="400px" height="200px" version="1.1" xmlns="http://www.w3.org/2000/svg">
<image x="0" y="50" width="200px" height="100px" href="data:image/png;base64,__base64data__" />
</svg>
And here is the result:
When I reduce x to -22 it looks fine, but it should be 0, shouldn't it?
<image x="-22" y="50" ...
How can I fix it? Where does the margin comes from?
Thanks a lot.

D3 removing old children and then appending new ones with their own attributes

I'm new to D3 and I need help with one task. When you click a button only text is overwritten but I want to remove all the children of the group with certain id and fill it with children of #refresh.
<?xml version="1.0"?>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=9" />
<style>
body {
background-color: #000000;
}</style>
</head>
<body>
<button onclick="refreshSvgElement('#c3a4ca3d-da2d-4b94-9a35-1088ba0cac19')">Change</button>
<svg id="refresh">
<text class="text" x="0.40576159954071" y="51.4495124816895" fill="#E0E0E0" font-family="Calibri" font-size="55.4" transform="matrix(1,0,0,1,200,200)">BLUE</text>
</svg>
<svg id="main_window" position="fixed" width="100%" height="100%" viewBox="0 0 8074 4098">
<g>
<g id="c3a4ca3d-da2d-4b94-9a35-1088ba0cac19">
<text class="text" x="0.40576159954071" y="51.4495124816895" fill="#E0E0E0" font-family="Calibri" font-size="55.4" transform="matrix(1,0,0,1,200,200)">RED</text>
</g>
</g>
</svg>
</body>
</html>
<script src="https://d3js.org/d3.v3.js"> </script>
<script>
function refreshSvgElement(id) {
var refreshElement = d3.select("#refresh");
var selection = d3.select(id)
.select("text")
<!-- .remove() -->
<!-- .append("text") -->
.text(refreshElement.text());
}
</script>
This is how I would do it. Store selection as a var, then select all current text and use .remove(), then append new text.
<?xml version="1.0"?>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=9" />
<style>
body {
background-color: white;
}</style>
</head>
<body>
<button onclick="refreshSvgElement('#c3a4ca3d-da2d-4b94-9a35-1088ba0cac19')">Change</button>
<svg id="refresh">
<text class="text" x="0.40576159954071" y="51.4495124816895" fill="#E0E0E0" font-family="Calibri" font-size="55.4" transform="matrix(1,0,0,1,200,200)">BLUE</text>
</svg>
<svg id="main_window" position="fixed" width="100%" height="100%" viewBox="0 0 8074 4098">
<g>
<g id="c3a4ca3d-da2d-4b94-9a35-1088ba0cac19">
<text class="text" x="0.40576159954071" y="51.4495124816895" fill="#E0E0E0" font-family="Calibri" font-size="55.4" transform="matrix(1,0,0,1,200,200)">RED</text>
</g>
</g>
</svg>
</body>
</html>
<script src="https://d3js.org/d3.v3.js"> </script>
<script>
function refreshSvgElement(id) {
var refreshElement = d3.select("#refresh");
console.log(refreshElement.text())
var selection = d3.select(id)
selection.selectAll("text").remove();
selection.append("text").text(refreshElement.text()).attr("x", "0.5").attr("y", "50");
}
</script>

d3 drag works but appear Uncaught TypeError: a.target.className.indexOf is not a function

I practice use d3 to drag svg circle around.
It works except following error appeared in console:
"Uncaught TypeError: a.target.className.indexOf is not a function"
What is wrong with my code? Following is my code:
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<title></title>
<meta charset="UTF-8">
<script src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<p>
<svg width="300" height="200">
<circle cx="100" cy="100" r="5" fill="red" />
<circle cx="50" cy="70" r="5" fill="red" />
</svg>
</p>
<script>
var drag = d3.behavior.drag()
.on("drag", function () {
d3.select(this).attr("cx", d3.event.x)
.attr("cy",d3.event.y);
});
d3.selectAll('circle').call(drag);
</script>
</body>
</html>
This is because of Google Translate extension. Disabling it solves the problem.
The object doesn't contain that method. This will "shim" it.
SVGAnimatedString.prototype.indexOf = function () { return this.baseVal.indexOf.apply(this.baseVal, arguments); }

d3.js not being referenced property in HTML

I currently have the following html.
<!DOCTYPE html>
<html>
<head>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script>
var circle = d3.selectAll("circle");
circle.style("fill", "steelblue");
circle.attr("r", 30);
</script>
</head>
<body>
<svg width="720" height="120">
<circle cx="40" cy="60" r="10"></circle>
<circle cx="80" cy="60" r="10"></circle>
<circle cx="120" cy="60" r="10"></circle>
</svg>
</body>
</html>
For some odd reason when I open the html. I don't get the simple results I expect. Anyone have idea why?
The problem is that the script is running before the dom is loaded. There are a couple of fixes, the simplest being to move the script to the end of the body.
<html>
<head>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
</head>
<body>
<svg width="720" height="120">
<circle cx="40" cy="60" r="10"></circle>
<circle cx="80" cy="60" r="10"></circle>
<circle cx="120" cy="60" r="10"></circle>
</svg>
<script>
var circle = d3.selectAll("circle");
circle.style("fill", "steelblue");
circle.attr("r", 30);
</script>
</body>
</html>
http://jsfiddle.net/46r21pn1/

svg innerHTML in firefox can not display

i use innerHTML to add svg element,it works fine in chrome but in firefox it can not display; thanks so much for any ansower
<!DOCTYPE html>
<html>
<head>
<title>SVGInnerHTML demo</title>
<meta charset="utf-8" />
<script src="svginnerhtml.js"></script>
<script>
alter = function () {
var svg = document.getElementById('container');
svg.innerHTML = '<rect width="100" height="60" fill="green" />'
+ '<circle cx="10" cy="19" r="20" fill="blue"></circle>'
+ '<text x="15" y="20" fill="white">hello world</text>'
+ '<g transform="translate(0, 70)"><rect width="100" height="20" fill="yellow" /></g>';
}
</script>
</head>
<body>
<svg id="container" width="100px" height="100px" http://www.w3.org/2000/svg>
</svg>
<p>
<button onclick="alter()">set .innerHTML</button>
<button onclick="alert(document.getElementById('container').innerHTML)">get .innerHTML</button>
</p>
</body>
</html>
A workaround is to add the innerHTML code as HTML, and not SVG. You can do that simply by using a <div> (instead of <svg>) in your HTML code as the placeholder, and insert the full SVG via innerHTML.
Replace:
<svg id="container" width="100px" height="100px">
</svg>
with
<div id="container" style="width: 100px; height: 100px">
</div>
And wrap your innerHTML string within an <svg> element:
var svg = document.getElementById('container');
svg.innerHTML = '<svg><rect width="100" height="60" fill="green" />'
+ '<circle cx="10" cy="19" r="20" fill="blue"></circle>'
+ '<text x="15" y="20" fill="white">hello world</text>'
+ '<g transform="translate(0, 70)">'
+ '<rect width="100" height="20" fill="yellow" /></g></svg>';
This should work in both Chrome and Firefox. Here's a JSFiddle.

Resources