Reputation: 109
I am trying to center
my append images
to the circle
but I cannot figure out how to set up my x
and y
since the size of the circle is dynamic and changes with the width of the svg
.
What is the formula for finding the x
and y
coordinates given the current radius of the circle?
vis
.enter()
.append("svg:image")
.attr("transform", d => "translate(" + d.x + "," + d.y + ")")
.attr("xlink:href", function(d) {
return d.img;
})
.attr("x", 0)
.attr("y", 0)
.attr("width", d => d.r / 1.5);
(function() {
var json = {
call_data: [
[
"Lifestyle",
1,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/5bb3ce2f801fbc657f83dd57_pp-lifestyle(white).svg"
],
[
"Sports",
10,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/5c9131911ad86f445cb5abc7_pp-sport(white).svg"
],
[
"Environment",
8,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/59f2a4bef42fff000159ba7a_pp-environ(white).svg"
],
[
"Medical",
6,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/59f2a4dc831e8500015fda53_pp-health(white).svg"
],
[
"Food",
4,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/59f8c2cc78cc2d0001fd4a7e_pp-food(white).svg"
]
]
};
var svg = d3
.select(".bubble_chart")
.append("svg")
/*
.attr("width", diameter)
.attr("height", diameter);
*/
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 600 400")
//class to make it responsive
.classed("svg-content-responsive", true);
var bubble = d3.layout
.pack()
.size([600, 400])
.value(function(d) {
return d.size;
})
.padding(2);
// generate data with calculated layout values
var nodes = bubble.nodes(processData(json)).filter(function(d) {
return !d.children;
}); // filter out the outer bubble
var vis = svg.selectAll("circle").data(nodes, function(d, i) {
return d.name + i;
});
vis
.enter()
.append("circle")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
})
.attr("class", function(d) {
return d.className;
})
.attr("r", 0)
.transition()
.duration(1000)
.attr("r", function(d) {
return d.r;
});
vis
.enter()
.append("svg:image")
.attr("transform", d => "translate(" + d.x + "," + d.y + ")")
.attr("xlink:href", function(d) {
return d.img;
})
.attr("x", 0)
.attr("y", 0)
.attr("width", d => d.r / 1.5);
function processData(data) {
var obj = data.call_data;
var newDataSet = [];
for (var prop in obj) {
newDataSet.push({
name: obj[prop][0],
className: obj[prop][0].toLowerCase(),
size: obj[prop][1],
img: obj[prop][2]
});
}
return {
children: newDataSet
};
}
})();
.lifestyle {
fill: #89BED3;
}
.sports {
fill: #2A83D4;
}
.environment {
fill: #6CC070;
}
.food {
fill: #665C9E;
}
.medical {
fill: #C13E40;
}
.bubble_chart {
border: 2px solid red;
display: inline-block;
position: absolute;
width: 100%;
padding-bottom: 100%;
/* aspect ratio */
vertical-align: top;
overflow: hidden;
}
.svg-content-responsive {
border: 3px solid green;
display: inline-block;
position: absolute;
top: 0;
left: 0;
}
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.5/d3.js"></script>
<div class="container">
<div class="bubble_chart"></div>
</div>
Upvotes: 0
Views: 940
Reputation: 5670
As you're already transforming the images using translate(" + d.x + "," + d.y + ")
which results in the images having the start point as the center of the corresponding circles, you just have to offset the images by their respective height and widths.
i.e. applying the following x, y attributes:
.attr('x', d => -(d.r/1.5)/2)
.attr('y', d => -(d.r/1.5)/2)
will center the images where (d.r/1.5)
is the width/height of the image.
Code snippet:
(function() {
var json = {
call_data: [
[
"Lifestyle",
1,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/5bb3ce2f801fbc657f83dd57_pp-lifestyle(white).svg"
],
[
"Sports",
10,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/5c9131911ad86f445cb5abc7_pp-sport(white).svg"
],
[
"Environment",
8,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/59f2a4bef42fff000159ba7a_pp-environ(white).svg"
],
[
"Medical",
6,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/59f2a4dc831e8500015fda53_pp-health(white).svg"
],
[
"Food",
4,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/59f8c2cc78cc2d0001fd4a7e_pp-food(white).svg"
]
]
};
var svg = d3
.select(".bubble_chart")
.append("svg")
/*
.attr("width", diameter)
.attr("height", diameter);
*/
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 600 400")
//class to make it responsive
.classed("svg-content-responsive", true);
var bubble = d3.layout
.pack()
.size([600, 400])
.value(function(d) {
return d.size;
})
.padding(2);
// generate data with calculated layout values
var nodes = bubble.nodes(processData(json)).filter(function(d) {
return !d.children;
}); // filter out the outer bubble
var vis = svg.selectAll("circle").data(nodes, function(d, i) {
return d.name + i;
});
vis
.enter()
.append("circle")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
})
.attr("class", function(d) {
return d.className;
})
.attr("r", 0)
.transition()
.duration(1000)
.attr("r", function(d) {
return d.r;
});
vis
.enter()
.append("svg:image").style('opacity', 0)
.attr("transform", d => "translate(" + d.x + "," + d.y + ")")
.attr('x', d => -(d.r/1.5)/2)
.attr('y', d => -(d.r/1.5)/2)
.attr("xlink:href", function(d) {
return d.img;
})
.attr("width", d => d.r / 1.5).transition().duration(1000).style('opacity', 1);
function processData(data) {
var obj = data.call_data;
var newDataSet = [];
for (var prop in obj) {
newDataSet.push({
name: obj[prop][0],
className: obj[prop][0].toLowerCase(),
size: obj[prop][1],
img: obj[prop][2]
});
}
return {
children: newDataSet
};
}
})();
.lifestyle {
fill: #89BED3;
}
.sports {
fill: #2A83D4;
}
.environment {
fill: #6CC070;
}
.food {
fill: #665C9E;
}
.medical {
fill: #C13E40;
}
.bubble_chart {
border: 2px solid red;
display: inline-block;
position: absolute;
width: 100%;
padding-bottom: 100%;
/* aspect ratio */
vertical-align: top;
overflow: hidden;
}
.svg-content-responsive {
border: 3px solid green;
display: inline-block;
position: absolute;
top: 0;
left: 0;
}
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.5/d3.js"></script>
<div class="container">
<div class="bubble_chart"></div>
</div>
Also, I've added an additional transition to the images' opacity to match with the circles visibility - .transition().duration(1000).style('opacity', 1)
. Hope this helps.
Upvotes: 1