How to center a text on a svg image using d3.js? - javascript

I am trying to put a text so that it is located in the center of my element as in the following image:
I would like this to be done dynamically depending on the size of my image.
How can I do it?
<body>
<script type="text/javascript">
const svg = d3.select("body").append("svg").attr("width",1000).attr("height",1000);
var widthMarker=50;
var img = svg.append("svg:image")
.attr("xlink:href", "marker.svg")
.attr("width", widthMarker)
.attr("height", widthMarker)
.attr("x", 228)
.attr("y",53);
svg.append("text").attr("width",100).attr("height",100).text("hello world");
</script>
</body>
http://plnkr.co/edit/39zEvnjOmotZXYF2GFwq?p=preview

You can simply put the image and text in a group container and adjust the text position relatively as shown below.
Plunker
const svg = d3.select("body")
.append("svg")
.attr("width", 1000)
.attr("height", 1000);
var widthMarker = 50;
var imgContainer = svg.append("g")
.attr("transform", "translate(228,53)");
var img = imgContainer.append("svg:image")
.attr("xlink:href", "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQgfLDf_0gBVxWp_7ec2UR3Dro5rBXquElgRdSH6K8LQQ7QanSQ")
.attr("width", widthMarker)
.attr("height", widthMarker);
var text = imgContainer.append("svg:text")
.attr("dy", widthMarker/2)
.text("hello world");
text.attr("dx", (widthMarker - text.node().getComputedTextLength()) / 2);
<script src="https://d3js.org/d3.v3.min.js"></script>

Related

Javascript: how to cover entire area?

I'm writing code for the first time with SVG. I created a small program in javascript. The rectangle does not start perfectly from the base of the area, remains a strip of light blue.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style type="text/css">
#graphicArea {
width: 1400px;
background: #a7def2;
}
</style>
</head>
<body>
<div id="outer-wrapper">
<div id="graphicArea"> </div>
</div>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
var width = 1400;
var height = 600;
var graphic;
var gocceAlSec = 7;
graphic = d3.select("#graphicArea").append("svg")
.attr("width", width)
.attr("height", height)
.attr("id", "graphic")
.attr("overflow", "hidden");
var dataset = [0];
graphic.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", 0)
.attr("y", 600)
.attr("width", 1400)
.attr("height", 0)
.style("fill", "blue")
.transition()
.duration(50000)
.attr("height", 600)
.attr("y", 0);
</script>
</body>
You're setting the background colour to the <div>, and because of that you'll have to deal with default margins, paddings, computed height etc...
A way simpler approach is setting the background colour to the SVG:
graphic = d3.select("#graphicArea").append("svg")
.attr("width", width)
.attr("height", height)
.attr("id", "graphic")
.style("background", "#a7def2")
Here is your code with that change:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div id="outer-wrapper">
<div id="graphicArea"> </div>
</div>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
var width = 1400;
var height = 600;
var graphic;
var gocceAlSec = 7;
graphic = d3.select("#graphicArea").append("svg")
.attr("width", width)
.attr("height", height)
.attr("id", "graphic")
.style("background", "#a7def2")
.attr("overflow", "hidden");
var dataset = [0];
graphic.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", 0)
.attr("y", 600)
.attr("width", 1400)
.attr("height", 0)
.style("fill", "blue")
.transition()
.duration(50000)
.attr("height", 600)
.attr("y", 0);
function makeRain() {
for (var i = 0; i < gocceAlSec; i++) {
startX = Math.random() * width,
startY = Math.random() * 100 - 100,
endX = startX;
endY = height + 200;
graphic.insert("circle")
.attr("cx", startX)
.attr("cy", startY)
.attr("r", 2)
.style("fill", "blue")
.transition()
.duration(2000)
.attr("cx", endX + 100)
.attr("cy", endY)
.remove();
};
}
d3.timer(makeRain, 100);
</script>
</body>
If you want to stick with the <div> style you can try some changes, like max-heigh: 600px;.
PS: Since this is your first D3/SVG code (by the way, kudos), here is a tip: you don't need an enter selection for the rect, not only because it's only one but mainly because the datum is meaningless. Just append the element to the container.

How to append SVG to the page using D3

So I have a .js file that contains a simple SVG that creates a square. Code below:
function load(){
var xmlns = "http://www.w3.org/2000/svg";
var foo = document.getElementById("printSquare");
var bar = document.createElementNS(xmlns, "svg");
var svgSquare = d3.select("div.output svg")
s.appendChild(svgSquare)
foo.appendChild(bar);
var square = svg.select("rect")
square.attr("width", 200)
square.attr("height", 200)
}
window.onload = load;
I want to append this square to an html file so I can open it in a browser and see the square. My HTML code as of right now:
<html>
<head>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script type="text/javascript" src="drawSquare.js"></script>
</head>
<body>
<div id="printSquare"></div>
</body>
</html>
Check out this fiddle - https://jsfiddle.net/s8capLx3/2/
If you want to just create a square and nothing else, there are 2 ways to go about it...
Use d3 symbols or 2. Use a rect (like you tried)
var data = [0];
var svg = d3.select('#printSquare').append('svg').attr('width',400).attr('height',200);
//symbols approach
svg.selectAll('.symbol')
.data(data)
.enter()
.append('path')
.attr('transform',function(d,i) { return 'translate('+(i*20+20 )+','+30+')';})
.attr('d', d3.symbol().type( function(d,i) { return d 3.symbols[3];}).size("200"));
//rect approach
svg.append("rect")
.attr("x", "200")
.attr("y", "10")
.attr("width", "75")
.attr("height", "75")
.attr("fill", "black");

Making svg container appear one below another on array looping

I have the following code where I created two svg container of different height and width and it is created for every element in the array. The code works well but I want the svg container text1 which contains title1 to appear below the svg container text2 that displays the title2 rather than side by side that's how it appears now, i.e., next to each other. How to make container 2 to appear just below the container 1
Here is the code
function draw(data) {
data.forEach(function(d) {
var text1 = d3.select("body").append("svg")
.attr("width", 200)
.attr("height", 100);
var title1 = d.values.title1;
text1.append("text")
.attr("x", "50%")
.attr("y", "10%")
.text(title1);
var text2 = d3.select("body").append("svg")
.attr("width", 300)
.attr("height", 500);
var title2 = d.values.title2;
text2.append("text")
.attr("x", "40%")
.attr("y", "10%")
.text(title2);
});
}
You probably can solve your problems just changing your CSS. By default, SVGs will display side by side, if there is enough room in the page. In this snippet, 5 SVGs are produced (click "run code snippet"):
var data = d3.range(5);
var body = d3.select("body");
var svg = body.selectAll("svg")
.data(data)
.enter()
.append("svg")
.attr("width", 100)
.attr("height", 100);
svg {
background-color: teal;
margin-right: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
This is exactly the same code, but setting the display in the CSS:
display: block;
Check the difference (click "run code snippet"):
var data = d3.range(5);
var body = d3.select("body");
var svg = body.selectAll("svg")
.data(data)
.enter()
.append("svg")
.attr("width", 100)
.attr("height", 100);
svg {
background-color: teal;
display: block;
margin-bottom: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

how to rotate any shape continuously in D3 js?

I am trying to call the update function to rotate the text by 1 degree and once the degree reaches 360 again the rotation angle becomes 0 and hence it will keep on rotating. But I think this is not the right way to approach the problem also it is not working. So suggest me the way to do it if anyone know it.
<script type="text/javascript" src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<script>
var width = 600;
var height = 300;
var holder = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
// draw the text
holder.append("text")
.style("fill", "black")
.style("font-size", "56px")
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.attr("transform", "translate(300,150) rotate(0)")
.text("Hi, how r u doing");
// Initial starting angle of the text
for(var i=0;i<=360;i++){
update(i);
if(i==360){i=0;}
}
var n;
// update the element
function update(n) {
// rotate the text
holder.select("text")
.transition()
.duration(2000)
.attr("transform", "translate(300,150) rotate("+n+")");
}
</script>
</body>
</html>
Example JS Fiddle here.
Your for loop never ends as you reset the counter i to 0 just before it finishes. If you remove this line, the code will have no visible result as the for loop executes so quickly, it's already completed before you can see anything.
A better solution is to use setInterval e.g.
var width = 600;
var height = 300;
var holder = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
// draw the text
holder.append("text")
.style("fill", "black")
.style("font-size", "56px")
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.attr("transform", "translate(300,150) rotate(0)")
.text("Hi, how r u doing");
// Initial starting angle of the text
var i = 0;
var timeInterval = 10;
setInterval(function(){
i += 1;
update(i % 360)
},timeInterval);
var n;
// update the element
function update(n) {
// rotate the text
holder.select("text")
.attr("transform", "translate(300,150) rotate("+n+")");
}
You can control the speed by adjusting the timeInterval variable.
I've added an example JS Fiddle here.

D3 adding donut chart within a tooltip

I'm trying to display a donut chart within a tooltip. I thought it'll be simply just adding the function name or creating the chart within .html() but that isn't the case sadly. Can anyone tell me where i'm going wrong?
Here's my code:
tooltip.select('.label').html(donutChart());
function donutChart(){
var dataset = {
hddrives: [20301672448, 9408258048, 2147483648, 21474836480, 35622912,32212254720],
};
var width = 460,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range(["#2DA7E2"]);
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 70);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var path = svg.selectAll("path")
.data(pie(dataset.hddrives))
.enter().append("path")
.attr("class", "arc")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc);
svg.append("text")
.attr("dy", ".35em")
.style("text-anchor", "middle")
.attr("class", "inside")
.text(function(d) { return 'Test'; });
}
Your function donutChart appends the <svg> to the body, not inside the tooltip.
A solution can be writing this in your .html():
.html("<h1>My Donut Chart</h1><br><svg class='myDonut'></svg>")
And then call your donutChart after that line, remembering to change your var svg:
var svg = d3.select(".myDonut")
Take care for not repeating the same variable names, even if they are inside a function (separate scope)... it can cause unnecessary confusion.

Categories

Resources