使D3.js堆叠条形图具有响应性

  • 本文关键字:响应 条形图 D3 js d3.js
  • 更新时间 :
  • 英文 :


我正在尝试获得一个D3.js(v5(堆叠条形图,以便相应地调整大小。我在处理标准条形图时也做过类似的事情,但关于包含堆叠条形图的新组的一些事情让我感到困惑。。。当前条形图调整大小,但保留以前的条形图。

这是一个CodePen的我合理的最小的示例代码。

在此基础上,以下是在页面加载和页面调整大小时调用的renderBars()函数:

function renderBars() {
// Calculating the x, y, width and height of a bar:
var barX = function(d, i) { return xScale(d.data.label); };
var barY = function(d) { return yScale(d[1]); };
var barW = xScale.bandwidth();
var barH = function(d) { return yScale(d[0]) - yScale(d[1]); };
// Surrounds all of the barGroups:
var barGroupsContainer = inner.append("g");
// One barGroup per kind/colour of bar:
var barGroups = barGroupsContainer
.selectAll(".bargroup")
.data(seriesData)
.enter().append("g")
.classed("bargroup", true)
.attr("fill", function(d) { return colors(d.key); });
// Each bar is within its barGroup:
var bars = barGroups
.selectAll("rect")
.data(function(d) { return d; });
// ENTER
bars
.enter().append("rect")
.attr("x", barX)
.attr("y", barY)
.attr("width", barW)
.attr("height", barH);
// UPDATE
bars
.transition()
.attr("x", barX)
.attr("y", barY)
.attr("width", barW)
.attr("height", barH);
// EXIT
bars.exit().remove();
}

我尝试过更新和删除barGroupsContainerbarGroups以及bars的各种组合,但没有任何改进。

(欢迎任何其他批评!(

更新:我不想使用preserveAspectRatio="xMinYMin meet"svg上的viewBox属性来做出响应——这会调整图表中的所有内容的大小,包括我不想要的任何文本。

耦合问题:

首先,barGroupsContainer变量的作用域(将其包含在renderBars函数中(意味着您正在创建一个父g,其他所有内容都将在每次重新调整大小时进入该父级。意思是每个元素总是";输入";。

其次,即使修复了在每组rects周围的包装g上没有正确处理enter/update模式的问题。您只处理了enter。。。

这里有一个快速重写:

// Prepare data
var data = [
{"label": "2000", "dogs": 23, "cats": 30, "fish": 5},
{"label": "2001", "dogs": 27, "cats": 19, "fish": 8},
{"label": "2002", "dogs": 35, "cats": 25, "fish": 10},
];
var groupKeys = Object.keys(data[0]).slice(1);
var seriesData = d3.stack().keys(groupKeys)(data)

// Initial dimensions and scales
var margin = {top: 0, right: 0, bottom: 0, left: 0};
var chartW;
var chartH;
var xScale = d3.scaleBand()
.domain(
data.map(function(d) { return d.label; })
);
var yScale = d3.scaleLinear()
.domain([
0,
d3.max(seriesData, function(d) { return d3.max(d, function(d) { return d[1]})})
]);
var colors = d3.scaleOrdinal()
.domain(groupKeys)
.range(['#e41a1c','#377eb8','#4daf4a'])
// Prepare containing elements.
var container = d3.select(".container");
var svg = container.append("svg");
var inner = svg.append("g");
// Surrounds all of the barGroups:
var barGroupsContainer = inner.append("g");
// Do initial render, and re-render on resize:
render();
window.addEventListener("resize", render);
function render() {
sizeChart();
renderBars();
}
function sizeChart() {
var width = parseInt(container.style("width"), 10);
var height = parseInt(container.style("height"), 10);
chartW = width - margin.left - margin.right;
chartH = height - margin.top - margin.bottom;
xScale.range([0, chartW]).padding(0.1);
yScale.rangeRound([chartH, 0]);
svg
.transition()
.attr("width", width)
.attr("height", height)
inner.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
}
function renderBars() {
// Calculating the x, y, width and height of a bar:
var barX = function(d, i) { return xScale(d.data.label); };
var barY = function(d) { return yScale(d[1]); };
var barW = xScale.bandwidth();
var barH = function(d) { return yScale(d[0]) - yScale(d[1]); };
// One barGroup per kind/colour of bar:

// ENTER
var barGroups = barGroupsContainer
.selectAll(".bargroup")
.data(seriesData);

// ENTER + UPDATE
barGroups = barGroups
.enter().append("g")
.merge(barGroups)
.classed("bargroup", true)
.attr("fill", function(d) { return colors(d.key); });

// Each bar is within its barGroup:
var bars = barGroups
.selectAll("rect")
.data(function(d) { 
return d; 
});
// ENTER
bars = bars
.enter().append("rect")
.merge(bars);
//.attr("x", barX)
//.attr("y", barY)
//.attr("width", barW)
//.attr("height", barH);
// UPDATE
bars
.transition()
.attr("x", barX)
.attr("y", barY)
.attr("width", barW)
.attr("height", barH);
// EXIT
bars.exit().remove();
}
.container {
width: 100%;
height: 300px;
}
<script src="https://d3js.org/d3.v5.js"></script>
<div class="container"></div>

将viewBox作为属性添加到SVG元素,然后在viewBox中设置宽度和高度。

因此,使用模板文字看起来像这样:

svg.attr('viewBox',`0 0 ${width} ${height}`)

如果你想让条形图从一行堆叠成一列,我会渲染3个SVG,然后使用CSS flexbox来处理随着屏幕大小的变化从一行切换到另一列。

最新更新