javascript - d3.js 气泡分布以匹配容器尺寸
问题描述
我想创建一个动态.container
,其中每个都circle
保留其size
比率并始终分布以适应.container
.
如何修改代码以使数据点的分布始终调整到边界的大小,.container
同时保持size
每个的比率circle
?
.container {
width: 400px;
height: 200px;
}
(function() {
var json = {
call_data: [
[
"Lifestyle",
1,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/5bb3ce2f801fbc657f83dd57_pp-lifestyle(white).svg"
],
[
"Sports",
2,
"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 width = 200;
var height = 200;
var tooltip = d3
.select(".bubble_chart")
.append("div")
.classed("tooltip", true);
var svg = d3
.select(".bubble_chart")
.append("svg")
//responsive SVG needs these 2 attributes and no width and height attr
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 " + width + " " + height);
var bubble = d3.layout
.pack()
.size([200, 200])
.value(function(d) {
return d.size;
})
.padding(12);
// 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("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);
/*
vis
.enter()
.append("text")
.attr("transform", d => "translate(" + d.x + "," + d.y + ")")
.attr("fill", "white")
.attr("text-anchor", "middle")
.attr("font-size", d => d.r / (d.r * 5 / 100))
.text(d => d.name);
*/
/* vis
.enter()
.append("text")
.attr("transform", d => "translate(" + d.x + "," + d.y + ")")
.attr("fill", "white")
.attr("text-anchor", "middle")
.attr("font-size", d => d.r / (d.r * 3 / 100))
.text(d => d.value);
*/
vis
.on("mousemove", function(d) {
tooltip
.style("opacity", 1)
.style("left", d3.event.x - tooltip.node().offsetWidth / 2 + "px")
.style("top", d3.event.y + 25 + "px").html(`
<p>Category: ${d.name}</p>
<p>Ordered: ${d.value}</p>
`);
})
.on("mouseout", function() {
tooltip.style("opacity", 0);
});
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
};
}
var aspect = width / height,
chart = d3.select('.bubble_chart');
d3.select(window)
.on("resize", function() {
var targetWidth = chart.node().getBoundingClientRect().width;
chart.attr("width", targetWidth);
chart.attr("height", targetWidth / aspect);
});
})();
.container {
border: 2px solid red;
width: 400px;
height: 200px;
}
.bubble_chart {
flex: 1;
border: 2px solid
}
.lifestyle {
fill: #89BED3;
}
.sports {
fill: #2A83D4;
}
.environment {
fill: #6CC070;
}
.food {
fill: #665C9E;
}
.medical {
fill: #C13E40;
}
.tooltip {
opacity: 0;
position: absolute;
pointer-events: none;
background-color: #fafafa;
border-radius: 8px;
padding: 15px;
z-index: 999;
box-shadow: 1px 1px 3px 0 rgba(0, 0, 0, .1)
}
.tooltip p {
margin: 0;
}
.tooltip:before {
content: " ";
position: absolute;
border: 12px solid transparent;
border-bottom-color: #fafafa;
top: -20px;
left: 50%;
margin-left: -12px;
}
<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>
解决方案
您应该在一开始就将宽度和高度设置为边界矩形高度和宽度。现在您将其设置为 200px,它们是相同的。
这样做:
var width = document.querySelector(".container").getBoundingClientRect().width;
var height = document.querySelector(".container").getBoundingClientRect().height;
(function() {
var json = {
call_data: [
[
"Lifestyle",
1,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/5bb3ce2f801fbc657f83dd57_pp-lifestyle(white).svg"
],
[
"Sports",
2,
"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 width = document.querySelector(".container").getBoundingClientRect().width;
var height = document.querySelector(".container").getBoundingClientRect().height;
var tooltip = d3
.select(".bubble_chart")
.append("div")
.classed("tooltip", true);
var svg = d3
.select(".bubble_chart")
.append("svg")
//responsive SVG needs these 2 attributes and no width and height attr
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 " + width + " " + height);
var bubble = d3.layout
.pack()
.size([200, 200])
.value(function(d) {
return d.size;
})
.padding(12);
// 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("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);
/*
vis
.enter()
.append("text")
.attr("transform", d => "translate(" + d.x + "," + d.y + ")")
.attr("fill", "white")
.attr("text-anchor", "middle")
.attr("font-size", d => d.r / (d.r * 5 / 100))
.text(d => d.name);
*/
/* vis
.enter()
.append("text")
.attr("transform", d => "translate(" + d.x + "," + d.y + ")")
.attr("fill", "white")
.attr("text-anchor", "middle")
.attr("font-size", d => d.r / (d.r * 3 / 100))
.text(d => d.value);
*/
vis
.on("mousemove", function(d) {
tooltip
.style("opacity", 1)
.style("left", d3.event.x - tooltip.node().offsetWidth / 2 + "px")
.style("top", d3.event.y + 25 + "px").html(`
<p>Category: ${d.name}</p>
<p>Ordered: ${d.value}</p>
`);
})
.on("mouseout", function() {
tooltip.style("opacity", 0);
});
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
};
}
var aspect = width / height,
chart = d3.select('.bubble_chart');
d3.select(window)
.on("resize", function() {
var targetWidth = chart.node().getBoundingClientRect().width;
chart.attr("width", targetWidth);
chart.attr("height", targetWidth / aspect);
});
})();
.container {
border: 2px solid red;
width: 400px;
height: 200px;
}
.bubble_chart {
flex: 1;
border: 2px solid
}
.lifestyle {
fill: #89BED3;
}
.sports {
fill: #2A83D4;
}
.environment {
fill: #6CC070;
}
.food {
fill: #665C9E;
}
.medical {
fill: #C13E40;
}
.tooltip {
opacity: 0;
position: absolute;
pointer-events: none;
background-color: #fafafa;
border-radius: 8px;
padding: 15px;
z-index: 999;
box-shadow: 1px 1px 3px 0 rgba(0, 0, 0, .1)
}
.tooltip p {
margin: 0;
}
.tooltip:before {
content: " ";
position: absolute;
border: 12px solid transparent;
border-bottom-color: #fafafa;
top: -20px;
left: 50%;
margin-left: -12px;
}
<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>
推荐阅读
- azure - Azure Kubernetes 部署
- python - 如何在不和谐的机器人 python 上添加权限限制
- c++ - 计算归一化立方体上的切线
- python - 使用标头和请求抓取 seloger.com
- javascript - 如何修复截断的字符串 json 以便能够再次解析它
- c# - 如何在执行插入或更新但不在 SqlKata 中获取时忽略属性
- python - 在多个数据帧之间进行选择
- javascript - 对带有正斜杠的 json 值感到困惑
- python - 为每个值分组数组中的所有其他值 - MongoDB
- reactjs - 在 React 应用程序标签中,链接不会重定向到另一个网站